diff --git a/src/.idea/.idea.Artemis/.idea/avalonia.xml b/src/.idea/.idea.Artemis/.idea/avalonia.xml index 6eb6336ba..a1aaa2a1a 100644 --- a/src/.idea/.idea.Artemis/.idea/avalonia.xml +++ b/src/.idea/.idea.Artemis/.idea/avalonia.xml @@ -18,8 +18,11 @@ + + + @@ -28,9 +31,13 @@ + + + + diff --git a/src/Artemis.UI.Shared/Services/ProfileEditor/IProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditor/IProfileEditorService.cs index 22167910d..7d1314755 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditor/IProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditor/IProfileEditorService.cs @@ -141,6 +141,20 @@ public interface IProfileEditorService : IArtemisSharedUIService /// The rounded time. TimeSpan RoundTime(TimeSpan time); + /// + /// Creates a new folder as a sibling or child of the given target. + /// + /// The target, if this is a layer the new layer will become a sibling, otherwise a child. + /// The resulting folder. + Folder CreateAndAddFolder(ProfileElement target); + + /// + /// Creates a new layer with the default brush and all current LEDs as a sibling or child of the given target. + /// + /// The target, if this is a layer the new layer will become a sibling, otherwise a child. + /// The resulting layer. + Layer CreateAndAddLayer(ProfileElement target); + /// /// Executes the provided command and adds it to the history. /// diff --git a/src/Artemis.UI.Shared/Services/ProfileEditor/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditor/ProfileEditorService.cs index 26968f208..5ec54e4f3 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditor/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditor/ProfileEditorService.cs @@ -18,6 +18,8 @@ internal class ProfileEditorService : IProfileEditorService private readonly BehaviorSubject _layerPropertySubject = new(null); private readonly ILogger _logger; private readonly IModuleService _moduleService; + private readonly IRgbService _rgbService; + private readonly ILayerBrushService _layerBrushService; private readonly BehaviorSubject _pixelsPerSecondSubject = new(120); private readonly BehaviorSubject _playingSubject = new(false); private readonly BehaviorSubject _profileConfigurationSubject = new(null); @@ -30,11 +32,18 @@ internal class ProfileEditorService : IProfileEditorService private readonly IWindowService _windowService; private ProfileEditorCommandScope? _profileEditorHistoryScope; - public ProfileEditorService(ILogger logger, IProfileService profileService, IModuleService moduleService, IWindowService windowService) + public ProfileEditorService(ILogger logger, + IProfileService profileService, + IModuleService moduleService, + IRgbService rgbService, + ILayerBrushService layerBrushService, + IWindowService windowService) { _logger = logger; _profileService = profileService; _moduleService = moduleService; + _rgbService = rgbService; + _layerBrushService = layerBrushService; _windowService = windowService; ProfileConfiguration = _profileConfigurationSubject.AsObservable(); @@ -293,6 +302,48 @@ internal class ProfileEditorService : IProfileEditorService return TimeSpan.FromMilliseconds(Math.Round(time.TotalMilliseconds)); } + /// + public Folder CreateAndAddFolder(ProfileElement target) + { + if (target is Layer targetLayer) + { + Folder folder = new(targetLayer.Parent, targetLayer.Parent.GetNewFolderName()); + ExecuteCommand(new AddProfileElement(folder, targetLayer.Parent, targetLayer.Order)); + return folder; + } + else + { + Folder folder = new(target, target.GetNewFolderName()); + ExecuteCommand(new AddProfileElement(folder, target, 0)); + return folder; + } + } + + /// + public Layer CreateAndAddLayer(ProfileElement target) + { + if (target is Layer targetLayer) + { + Layer layer = new(targetLayer.Parent, targetLayer.GetNewLayerName()); + _layerBrushService.ApplyDefaultBrush(layer); + + layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds)); + ExecuteCommand(new AddProfileElement(layer, targetLayer.Parent, targetLayer.Order)); + + return layer; + } + else + { + Layer layer = new(target, target.GetNewLayerName()); + _layerBrushService.ApplyDefaultBrush(layer); + + layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds)); + ExecuteCommand(new AddProfileElement(layer, target, 0)); + + return layer; + } + } + public void ChangePixelsPerSecond(int pixelsPerSecond) { _pixelsPerSecondSubject.OnNext(pixelsPerSecond); diff --git a/src/Artemis.UI/MainWindow.axaml b/src/Artemis.UI/MainWindow.axaml index f10f4287f..5228ca673 100644 --- a/src/Artemis.UI/MainWindow.axaml +++ b/src/Artemis.UI/MainWindow.axaml @@ -7,9 +7,15 @@ x:Class="Artemis.UI.MainWindow" Icon="/Assets/Images/Logo/application.ico" Title="Artemis 2.0"> - + - + + + + + + + diff --git a/src/Artemis.UI/MainWindow.axaml.cs b/src/Artemis.UI/MainWindow.axaml.cs index 14dbd90b5..de5ee0368 100644 --- a/src/Artemis.UI/MainWindow.axaml.cs +++ b/src/Artemis.UI/MainWindow.axaml.cs @@ -12,15 +12,28 @@ namespace Artemis.UI { public class MainWindow : ReactiveCoreWindow { + private readonly Panel _rootPanel; + private readonly ContentControl _sidebarContentControl; + public MainWindow() { Opened += OnOpened; InitializeComponent(); + _rootPanel = this.Get("RootPanel"); + _sidebarContentControl = this.Get("SidebarContentControl"); + _rootPanel.LayoutUpdated += OnLayoutUpdated; + #if DEBUG this.AttachDevTools(); #endif } + // TODO: Replace with a media query once https://github.com/AvaloniaUI/Avalonia/pull/7938 is implemented + private void OnLayoutUpdated(object? sender, EventArgs e) + { + _sidebarContentControl.Width = _rootPanel.Bounds.Width >= 1800 ? 300 : 240; + } + private void OnOpened(object? sender, EventArgs e) { Opened -= OnOpened; @@ -32,12 +45,6 @@ namespace Artemis.UI } } - private void SetupTitlebar() - { - - - } - private void InitializeComponent() { AvaloniaXamlLoader.Load(this); diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/AlwaysOnConditionView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/AlwaysOnConditionView.axaml index e703f4359..0f18dd967 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/AlwaysOnConditionView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/AlwaysOnConditionView.axaml @@ -6,11 +6,11 @@ mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="450" x:Class="Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes.AlwaysOnConditionView"> - - + + - After playing the start segment, the main segment is endlessly repeated. - + After playing the start segment, the main segment is endlessly repeated. + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionView.axaml index ca34c4639..d45a21c9f 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionView.axaml @@ -8,18 +8,18 @@ x:Class="Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes.EventConditionView" x:DataType="conditionTypes:EventConditionViewModel"> - - - + + + Triggered by event + IsEventPicker="True" /> When the event fires.. @@ -54,11 +54,11 @@ DockPanel.Dock="Top" SelectedIndex="{CompiledBinding SelectedToggleOffMode}" IsVisible="{CompiledBinding ShowToggleOffOptions}"> - Finish the main segment + Finish the main segment Skip forward to the end segment - diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml index e3a38b5e6..e6cd7d39d 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml @@ -7,212 +7,193 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.ProfileEditor.MenuBar.MenuBarView" x:DataType="menuBar:MenuBarViewModel"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + - + - - + - + - - + - + - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml.cs index 469ca47de..f29875c7f 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml.cs @@ -2,23 +2,21 @@ using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.ProfileEditor.MenuBar +namespace Artemis.UI.Screens.ProfileEditor.MenuBar; + +public class MenuBarView : ReactiveUserControl { - public partial class MenuBarView : ReactiveUserControl + public MenuBarView() { - public MenuBarView() - { - InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - - private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e) - { - - } + InitializeComponent(); } -} + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e) + { + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs index 9f5e7369f..532441416 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs @@ -1,31 +1,50 @@ using System; +using System.Diagnostics; +using System.IO; +using System.Linq; using System.Reactive; using System.Reactive.Disposables; using System.Reactive.Linq; +using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; +using Artemis.UI.Screens.Sidebar; using Artemis.UI.Shared; +using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.ProfileEditor; +using Artemis.UI.Shared.Services.ProfileEditor.Commands; +using Newtonsoft.Json; using ReactiveUI; +using Serilog; namespace Artemis.UI.Screens.ProfileEditor.MenuBar; public class MenuBarViewModel : ActivatableViewModelBase { + private readonly ILogger _logger; + private readonly IProfileEditorService _profileEditorService; private readonly IProfileService _profileService; private readonly ISettingsService _settingsService; + private readonly IWindowService _windowService; private ProfileEditorHistory? _history; - private ObservableAsPropertyHelper? _profileConfiguration; + private ObservableAsPropertyHelper? _suspendedEditing; private ObservableAsPropertyHelper? _isSuspended; + private ObservableAsPropertyHelper? _profileConfiguration; + private ObservableAsPropertyHelper? _profileElement; - public MenuBarViewModel(IProfileEditorService profileEditorService, IProfileService profileService, ISettingsService settingsService) + public MenuBarViewModel(ILogger logger, IProfileEditorService profileEditorService, IProfileService profileService, ISettingsService settingsService, IWindowService windowService) { + _logger = logger; + _profileEditorService = profileEditorService; _profileService = profileService; _settingsService = settingsService; + _windowService = windowService; this.WhenActivated(d => { profileEditorService.History.Subscribe(history => History = history).DisposeWith(d); _profileConfiguration = profileEditorService.ProfileConfiguration.ToProperty(this, vm => vm.ProfileConfiguration).DisposeWith(d); + _profileElement = profileEditorService.ProfileElement.ToProperty(this, vm => vm.ProfileElement).DisposeWith(d); + _suspendedEditing = profileEditorService.SuspendedEditing.ToProperty(this, vm => vm.SuspendedEditing).DisposeWith(d); _isSuspended = profileEditorService.ProfileConfiguration .Select(p => p?.WhenAnyValue(c => c.IsSuspended) ?? Observable.Never()) .Switch() @@ -33,17 +52,35 @@ public class MenuBarViewModel : ActivatableViewModelBase .DisposeWith(d); }); + AddFolder = ReactiveCommand.Create(ExecuteAddFolder); + AddLayer = ReactiveCommand.Create(ExecuteAddLayer); + ViewProperties = ReactiveCommand.CreateFromTask(ExecuteViewProperties, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null)); + ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null)); + DeleteProfile = ReactiveCommand.CreateFromTask(ExecuteDeleteProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null)); + ExportProfile = ReactiveCommand.CreateFromTask(ExecuteExportProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null)); + DuplicateProfile = ReactiveCommand.Create(ExecuteDuplicateProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null)); + ToggleSuspendedEditing = ReactiveCommand.Create(ExecuteToggleSuspendedEditing); ToggleBooleanSetting = ReactiveCommand.Create>(ExecuteToggleBooleanSetting); + OpenUri = ReactiveCommand.CreateFromTask(ExecuteOpenUri); } - private void ExecuteToggleBooleanSetting(PluginSetting setting) - { - setting.Value = !setting.Value; - setting.Save(); - } - + public ReactiveCommand AddFolder { get; } + public ReactiveCommand AddLayer { get; } + public ReactiveCommand ToggleSuspended { get; } + public ReactiveCommand ViewProperties { get; } + public ReactiveCommand DeleteProfile { get; } + public ReactiveCommand ExportProfile { get; } + public ReactiveCommand DuplicateProfile { get; } public ReactiveCommand, Unit> ToggleBooleanSetting { get; } + public ReactiveCommand OpenUri { get; } + public ReactiveCommand ToggleSuspendedEditing { get; } + public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value; + public RenderProfileElement? ProfileElement => _profileElement?.Value; + public bool IsSuspended => _isSuspended?.Value ?? false; + public bool SuspendedEditing => _suspendedEditing?.Value ?? false; + + public PluginSetting AutoSuspend => _settingsService.GetSetting("ProfileEditor.AutoSuspend", true); public PluginSetting FocusSelectedLayer => _settingsService.GetSetting("ProfileEditor.FocusSelectedLayer", false); public PluginSetting ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); public PluginSetting ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false); @@ -56,16 +93,113 @@ public class MenuBarViewModel : ActivatableViewModelBase set => RaiseAndSetIfChanged(ref _history, value); } - public bool IsSuspended + private void ExecuteAddFolder() { - get => _isSuspended?.Value ?? false; - set - { - if (ProfileConfiguration == null) - return; + if (ProfileConfiguration?.Profile == null) + return; - ProfileConfiguration.IsSuspended = value; - _profileService.SaveProfileCategory(ProfileConfiguration.Category); + RenderProfileElement target = ProfileElement ?? ProfileConfiguration.Profile.GetRootFolder(); + _profileEditorService.CreateAndAddFolder(target); + } + + private void ExecuteAddLayer() + { + if (ProfileConfiguration?.Profile == null) + return; + + RenderProfileElement target = ProfileElement ?? ProfileConfiguration.Profile.GetRootFolder(); + _profileEditorService.CreateAndAddLayer(target); + } + + private async Task ExecuteViewProperties() + { + if (ProfileConfiguration == null) + return; + + await _windowService.ShowDialogAsync( + ("profileCategory", ProfileConfiguration.Category), + ("profileConfiguration", ProfileConfiguration) + ); + } + + private void ExecuteToggleSuspended() + { + if (ProfileConfiguration == null) + return; + + ProfileConfiguration.IsSuspended = !ProfileConfiguration.IsSuspended; + _profileService.SaveProfileCategory(ProfileConfiguration.Category); + } + + private async Task ExecuteDeleteProfile() + { + if (ProfileConfiguration == null) + return; + if (!await _windowService.ShowConfirmContentDialog("Delete profile", "Are you sure you want to permanently delete this profile?")) + return; + + if (ProfileConfiguration.IsBeingEdited) + _profileEditorService.ChangeCurrentProfileConfiguration(null); + _profileService.RemoveProfileConfiguration(ProfileConfiguration); + } + + private async Task ExecuteExportProfile() + { + if (ProfileConfiguration == null) + return; + + // Might not cover everything but then the dialog will complain and that's good enough + string fileName = Path.GetInvalidFileNameChars().Aggregate(ProfileConfiguration.Name, (current, c) => current.Replace(c, '-')); + string? result = await _windowService.CreateSaveFileDialog() + .HavingFilter(f => f.WithExtension("json").WithName("Artemis profile")) + .WithInitialFileName(fileName) + .ShowAsync(); + + if (result == null) + return; + + ProfileConfigurationExportModel export = _profileService.ExportProfile(ProfileConfiguration); + string json = JsonConvert.SerializeObject(export, IProfileService.ExportSettings); + try + { + await File.WriteAllTextAsync(result, json); + } + catch (Exception e) + { + _windowService.ShowExceptionDialog("Failed to export profile", e); + } + } + + private void ExecuteDuplicateProfile() + { + if (ProfileConfiguration == null) + return; + + ProfileConfigurationExportModel export = _profileService.ExportProfile(ProfileConfiguration); + _profileService.ImportProfile(ProfileConfiguration.Category, export, true, false, "copy"); + } + + private void ExecuteToggleSuspendedEditing() + { + _profileEditorService.ChangeSuspendedEditing(!SuspendedEditing); + } + + private void ExecuteToggleBooleanSetting(PluginSetting setting) + { + setting.Value = !setting.Value; + setting.Save(); + } + + private async Task ExecuteOpenUri(string uri) + { + try + { + Process.Start(new ProcessStartInfo(uri) {UseShellExecute = true, Verb = "open"}); + } + catch (Exception e) + { + _logger.Error(e, "Failed to open URL"); + await _windowService.ShowConfirmContentDialog("Failed to open URL", "We couldn't open the URL for you, check the logs for more details", "Confirm", null); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackView.axaml index ef8291e1d..eee77fd99 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackView.axaml @@ -60,6 +60,6 @@ - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackView.axaml.cs index ed5b99c6b..d94c76117 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackView.axaml.cs @@ -1,18 +1,17 @@ using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.ProfileEditor.Playback -{ - public partial class PlaybackView : ReactiveUserControl - { - public PlaybackView() - { - InitializeComponent(); - } +namespace Artemis.UI.Screens.ProfileEditor.Playback; - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } +public class PlaybackView : ReactiveUserControl +{ + public PlaybackView() + { + InitializeComponent(); } -} + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackViewModel.cs index a07d4aa6f..491c05be6 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Playback/PlaybackViewModel.cs @@ -14,14 +14,14 @@ public class PlaybackViewModel : ActivatableViewModelBase { private readonly IProfileEditorService _profileEditorService; private readonly ISettingsService _settingsService; - private RenderProfileElement? _profileElement; private ObservableAsPropertyHelper? _currentTime; private ObservableAsPropertyHelper? _formattedCurrentTime; - private ObservableAsPropertyHelper? _playing; - private bool _repeating; - private bool _repeatTimeline; - private bool _repeatSegment; private DateTime _lastUpdate; + private ObservableAsPropertyHelper? _playing; + private RenderProfileElement? _profileElement; + private bool _repeating; + private bool _repeatSegment; + private bool _repeatTimeline; public PlaybackViewModel(IProfileEditorService profileEditorService, ISettingsService settingsService) { diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs index d0d493842..13c9deefd 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Threading.Tasks; using Artemis.Core; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile; using Artemis.UI.Extensions; using Artemis.UI.Ninject.Factories; @@ -14,21 +13,14 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree; public class FolderTreeItemViewModel : TreeItemViewModel { - public FolderTreeItemViewModel(TreeItemViewModel? parent, - Folder folder, - IWindowService windowService, - IProfileEditorService profileEditorService, - ILayerBrushService layerBrushService, - IProfileEditorVmFactory profileEditorVmFactory, - IRgbService rgbService) - : base(parent, folder, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory) + public FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder, IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory) + : base(parent, folder, windowService, profileEditorService, profileEditorVmFactory) { Folder = folder; } public Folder Folder { get; } - #region Overrides of TreeItemViewModel protected override async Task ExecuteDuplicate() diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs index 77919e2bc..7a8e24eee 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Threading.Tasks; using Artemis.Core; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile; using Artemis.UI.Extensions; using Artemis.UI.Ninject.Factories; @@ -14,14 +13,8 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree; public class LayerTreeItemViewModel : TreeItemViewModel { - public LayerTreeItemViewModel(TreeItemViewModel? parent, - Layer layer, - IWindowService windowService, - IProfileEditorService profileEditorService, - IRgbService rgbService, - ILayerBrushService layerBrushService, - IProfileEditorVmFactory profileEditorVmFactory) - : base(parent, layer, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory) + public LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer, IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory) + : base(parent, layer, windowService, profileEditorService, profileEditorVmFactory) { Layer = layer; } diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeViewModel.cs index 458ce9a42..111df1c7c 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeViewModel.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Reactive.Disposables; using System.Threading.Tasks; using Artemis.Core; -using Artemis.Core.Services; using Artemis.UI.Ninject.Factories; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.ProfileEditor; @@ -18,12 +17,8 @@ public class ProfileTreeViewModel : TreeItemViewModel private readonly IProfileEditorService _profileEditorService; private TreeItemViewModel? _selectedChild; - public ProfileTreeViewModel(IWindowService windowService, - IProfileEditorService profileEditorService, - ILayerBrushService layerBrushService, - IProfileEditorVmFactory profileEditorVmFactory, - IRgbService rgbService) - : base(null, null, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory) + public ProfileTreeViewModel(IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory) + : base(null, null, windowService, profileEditorService, profileEditorVmFactory) { _profileEditorService = profileEditorService; this.WhenActivated(d => diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs index c9d3ae8f4..fe2315ced 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs @@ -7,7 +7,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; -using Artemis.Core.Services; using Artemis.UI.Extensions; using Artemis.UI.Ninject.Factories; using Artemis.UI.Shared; @@ -21,9 +20,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree; public abstract class TreeItemViewModel : ActivatableViewModelBase { - private readonly ILayerBrushService _layerBrushService; private readonly IProfileEditorVmFactory _profileEditorVmFactory; - private readonly IRgbService _rgbService; private readonly IWindowService _windowService; protected readonly IProfileEditorService ProfileEditorService; private bool _canPaste; @@ -34,16 +31,13 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase private string? _renameValue; private bool _renaming; - protected TreeItemViewModel(TreeItemViewModel? parent, ProfileElement? profileElement, + protected TreeItemViewModel(TreeItemViewModel? parent, + ProfileElement? profileElement, IWindowService windowService, IProfileEditorService profileEditorService, - IRgbService rgbService, - ILayerBrushService layerBrushService, IProfileEditorVmFactory profileEditorVmFactory) { ProfileEditorService = profileEditorService; - _rgbService = rgbService; - _layerBrushService = layerBrushService; _windowService = windowService; _profileEditorVmFactory = profileEditorVmFactory; @@ -126,9 +120,10 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase foreach (IBreakableModel current in broken) { _windowService.ShowExceptionDialog($"{current.BrokenDisplayName} - {current.BrokenState}", current.BrokenStateException!); - if (broken.Last() != current) - if (!await _windowService.ShowConfirmContentDialog("Broken state", "Do you want to view the next exception?")) - return; + if (broken.Last() == current) + continue; + if (!await _windowService.ShowConfirmContentDialog("Broken state", "Do you want to view the next exception?")) + return; } } @@ -243,30 +238,14 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase private void ExecuteAddFolder() { - if (ProfileElement is Layer targetLayer) - ProfileEditorService.ExecuteCommand(new AddProfileElement(new Folder(targetLayer.Parent, targetLayer.Parent.GetNewFolderName()), targetLayer.Parent, targetLayer.Order)); - else if (ProfileElement != null) - ProfileEditorService.ExecuteCommand(new AddProfileElement(new Folder(ProfileElement, ProfileElement.GetNewFolderName()), ProfileElement, 0)); + if (ProfileElement != null) + ProfileEditorService.CreateAndAddFolder(ProfileElement); } private void ExecuteAddLayer() { - if (ProfileElement is Layer targetLayer) - { - Layer layer = new(targetLayer.Parent, targetLayer.GetNewLayerName()); - _layerBrushService.ApplyDefaultBrush(layer); - - layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds)); - ProfileEditorService.ExecuteCommand(new AddProfileElement(layer, targetLayer.Parent, targetLayer.Order)); - } - else if (ProfileElement != null) - { - Layer layer = new(ProfileElement, ProfileElement.GetNewLayerName()); - _layerBrushService.ApplyDefaultBrush(layer); - - layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds)); - ProfileEditorService.ExecuteCommand(new AddProfileElement(layer, ProfileElement, 0)); - } + if (ProfileElement != null) + ProfileEditorService.CreateAndAddLayer(ProfileElement); } private async void UpdateCanPaste(bool isFlyoutOpen) diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml index aaa28b4f8..d102a1eb5 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml @@ -27,7 +27,7 @@ HorizontalAlignment="Right" Margin="10" Command="{Binding OpenEditor}"> - + @@ -42,7 +42,7 @@ When you enable data bindings you can no longer use keyframes or normal values for this property. - Learn more diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml.cs index a3d257b4b..d38d4272f 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml.cs @@ -1,18 +1,17 @@ using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.ProfileEditor.Properties.DataBinding -{ - public partial class DataBindingView : ReactiveUserControl - { - public DataBindingView() - { - InitializeComponent(); - } +namespace Artemis.UI.Screens.ProfileEditor.Properties.DataBinding; - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } +public class DataBindingView : ReactiveUserControl +{ + public DataBindingView() + { + InitializeComponent(); } -} + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectView.axaml index 3fec4881e..6cba34e15 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectView.axaml @@ -11,7 +11,7 @@ x:DataType="dialogs:AddEffectViewModel" Width="500"> - + - - + - + None of the effects match your search - + - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectViewModel.cs index 3193351f0..0f5c844e4 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectViewModel.cs @@ -14,8 +14,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Dialogs; public class AddEffectViewModel : ContentDialogViewModelBase { - private readonly RenderProfileElement _renderProfileElement; private readonly IProfileEditorService _profileEditorService; + private readonly RenderProfileElement _renderProfileElement; private string? _searchText; public AddEffectViewModel(RenderProfileElement renderProfileElement, IProfileEditorService profileEditorService, ILayerEffectService layerEffectService) @@ -39,7 +39,7 @@ public class AddEffectViewModel : ContentDialogViewModelBase public string? SearchText { get => _searchText; - set => this.RaiseAndSetIfChanged(ref _searchText, value); + set => RaiseAndSetIfChanged(ref _searchText, value); } public void AddLayerEffect(LayerEffectDescriptor descriptor) @@ -58,5 +58,4 @@ public class AddEffectViewModel : ContentDialogViewModelBase return data => data.DisplayName.Contains(search, StringComparison.InvariantCultureIgnoreCase) || data.Description.Contains(search, StringComparison.InvariantCultureIgnoreCase); } -} - +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesView.axaml index 7d755037a..078e31fe5 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesView.axaml @@ -5,7 +5,6 @@ xmlns:controls="clr-namespace:Artemis.UI.Controls" xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties" xmlns:converters="clr-namespace:Artemis.UI.Converters" - xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="350" x:Class="Artemis.UI.Screens.ProfileEditor.Properties.PropertiesView" x:DataType="local:PropertiesViewModel"> @@ -13,7 +12,7 @@ - + @@ -89,8 +88,7 @@ StartPoint="0,0" EndPoint="{CompiledBinding #ContainerGrid.Bounds.BottomLeft}" StrokeThickness="2" - Stroke="{DynamicResource SystemAccentColorLight1}"> - + Stroke="{DynamicResource SystemAccentColorLight1}" /> - + Opacity="0.5" /> - + Opacity="0.5" /> - + Opacity="0.5" /> - + Fill="{DynamicResource SystemAccentColorLight1}" /> _cachedPropertyViewModels; private readonly IDataBindingVmFactory _dataBindingVmFactory; - private readonly IWindowService _windowService; private readonly ILayerEffectService _layerEffectService; private readonly ILayerPropertyVmFactory _layerPropertyVmFactory; private readonly IProfileEditorService _profileEditorService; private readonly ISettingsService _settingsService; + private readonly IWindowService _windowService; private DataBindingViewModel? _backgroundDataBindingViewModel; private DataBindingViewModel? _dataBindingViewModel; private ObservableAsPropertyHelper? _layerProperty; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineEasingView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineEasingView.axaml index 4dace623e..e925b4edb 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineEasingView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineEasingView.axaml @@ -16,4 +16,4 @@ Margin="0 0 10 0" /> - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineEasingView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineEasingView.axaml.cs index 537c6a2a6..fa1d2f160 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineEasingView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineEasingView.axaml.cs @@ -1,18 +1,17 @@ using Avalonia.Controls; using Avalonia.Markup.Xaml; -namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes -{ - public partial class TimelineEasingView : UserControl - { - public TimelineEasingView() - { - InitializeComponent(); - } +namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes; - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } +public class TimelineEasingView : UserControl +{ + public TimelineEasingView() + { + InitializeComponent(); } -} + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeView.axaml index a08f48bd2..38ad8293c 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeView.axaml @@ -44,8 +44,8 @@ - - + + diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeView.axaml.cs index f2c11e72e..ea1a6c5ff 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeView.axaml.cs @@ -8,9 +8,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes; public class TimelineKeyframeView : ReactiveUserControl { + private bool _moved; private TimelinePropertyView? _timelinePropertyView; private TimelineView? _timelineView; - private bool _moved; public TimelineKeyframeView() { @@ -70,7 +70,9 @@ public class TimelineKeyframeView : ReactiveUserControl : ActivatableViewModelBase, ITimelineKeyframeViewModel { private readonly IProfileEditorService _profileEditorService; + private ObservableAsPropertyHelper? _isSelected; + private string _timestamp; private double _x; - private string _timestamp; - private ObservableAsPropertyHelper? _isSelected; public TimelineKeyframeViewModel(LayerPropertyKeyframe layerPropertyKeyframe, IProfileEditorService profileEditorService) { @@ -56,16 +56,16 @@ public class TimelineKeyframeViewModel : ActivatableViewModelBase, ITimelineK set => RaiseAndSetIfChanged(ref _timestamp, value); } - public bool IsSelected => _isSelected?.Value ?? false; - public TimeSpan Position => LayerPropertyKeyframe.Position; - public ILayerPropertyKeyframe Keyframe => LayerPropertyKeyframe; - public void Update() { X = _pixelsPerSecond * LayerPropertyKeyframe.Position.TotalSeconds; Timestamp = $"{Math.Floor(LayerPropertyKeyframe.Position.TotalSeconds):00}.{LayerPropertyKeyframe.Position.Milliseconds:000}"; } + public bool IsSelected => _isSelected?.Value ?? false; + public TimeSpan Position => LayerPropertyKeyframe.Position; + public ILayerPropertyKeyframe Keyframe => LayerPropertyKeyframe; + /// public void Select(bool expand, bool toggle) { @@ -157,12 +157,11 @@ public class TimelineKeyframeViewModel : ActivatableViewModelBase, ITimelineK .Cast() .Select(e => new TimelineEasingViewModel(e, Keyframe))); } - + public void SelectEasingFunction(Easings.Functions easingFunction) { _profileEditorService.ExecuteCommand(new ChangeKeyframeEasing(Keyframe, easingFunction)); } #endregion -} - +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentView.axaml index 85cd1dcae..20ad810f4 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentView.axaml @@ -28,7 +28,7 @@ IsVisible="{CompiledBinding ShowAddMain}"> - + - + ToolTip.Tip="{CompiledBinding EndTimestamp}" /> \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentView.axaml.cs index 1bf4c584e..1560dc8fe 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentView.axaml.cs @@ -4,47 +4,46 @@ using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments +namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments; + +public class EndSegmentView : ReactiveUserControl { - public partial class EndSegmentView : ReactiveUserControl + private readonly Rectangle _keyframeDragAnchor; + private double _dragOffset; + + public EndSegmentView() { - private readonly Rectangle _keyframeDragAnchor; - private double _dragOffset; + InitializeComponent(); + _keyframeDragAnchor = this.Get("KeyframeDragAnchor"); + } - public EndSegmentView() - { - InitializeComponent(); - _keyframeDragAnchor = this.Get("KeyframeDragAnchor"); - } + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } + private void KeyframeDragAnchor_OnPointerPressed(object? sender, PointerPressedEventArgs e) + { + if (ViewModel == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) + return; + e.Pointer.Capture(_keyframeDragAnchor); - private void KeyframeDragAnchor_OnPointerPressed(object? sender, PointerPressedEventArgs e) - { - if (ViewModel == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) - return; - e.Pointer.Capture(_keyframeDragAnchor); + _dragOffset = ViewModel.Width - e.GetCurrentPoint(this).Position.X; + ViewModel.StartResize(); + } - _dragOffset = ViewModel.Width - e.GetCurrentPoint(this).Position.X; - ViewModel.StartResize(); - } + private void KeyframeDragAnchor_OnPointerMoved(object? sender, PointerEventArgs e) + { + if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) + return; + ViewModel.UpdateResize(e.GetCurrentPoint(this).Position.X + _dragOffset); + } - private void KeyframeDragAnchor_OnPointerMoved(object? sender, PointerEventArgs e) - { - if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) - return; - ViewModel.UpdateResize(e.GetCurrentPoint(this).Position.X + _dragOffset); - } - - private void KeyframeDragAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e) - { - if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) - return; - e.Pointer.Capture(null); - ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset); - } + private void KeyframeDragAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e) + { + if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) + return; + e.Pointer.Capture(null); + ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentViewModel.cs index 2aa379786..16817896d 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/EndSegmentViewModel.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Reactive.Linq; using Artemis.Core; using Artemis.UI.Shared.Services.ProfileEditor; @@ -13,14 +11,14 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments; public class EndSegmentViewModel : TimelineSegmentViewModel { private readonly IProfileEditorService _profileEditorService; - private RenderProfileElement? _profileElement; - private int _pixelsPerSecond; - private TimeSpan _time; - private ObservableAsPropertyHelper? _start; + private readonly ObservableAsPropertyHelper _width; private ObservableAsPropertyHelper? _end; private ObservableAsPropertyHelper? _endTimestamp; - private readonly ObservableAsPropertyHelper _width; private TimeSpan _initialLength; + private int _pixelsPerSecond; + private RenderProfileElement? _profileElement; + private ObservableAsPropertyHelper? _start; + private TimeSpan _time; public EndSegmentViewModel(IProfileEditorService profileEditorService) : base(profileEditorService) @@ -59,6 +57,7 @@ public class EndSegmentViewModel : TimelineSegmentViewModel public override double StartX => _start?.Value ?? 0; public override TimeSpan End => _profileElement?.Timeline.EndSegmentEndPosition ?? TimeSpan.Zero; public override double EndX => _end?.Value ?? 0; + public override TimeSpan Length { get => _profileElement?.Timeline.EndSegmentLength ?? TimeSpan.Zero; @@ -70,7 +69,7 @@ public class EndSegmentViewModel : TimelineSegmentViewModel } public override double Width => _width.Value; - + public override string? EndTimestamp => _endTimestamp?.Value; public override ResizeTimelineSegment.SegmentType Type => ResizeTimelineSegment.SegmentType.End; } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/MainSegmentView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/MainSegmentView.axaml index 8e1ac2788..031bc44b5 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/MainSegmentView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/MainSegmentView.axaml @@ -58,7 +58,7 @@ - + ToolTip.Tip="{CompiledBinding EndTimestamp}" /> \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/MainSegmentView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/MainSegmentView.axaml.cs index b84bfe04f..c138bc0f9 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/MainSegmentView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/MainSegmentView.axaml.cs @@ -4,59 +4,58 @@ using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments +namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments; + +public class MainSegmentView : ReactiveUserControl { - public partial class MainSegmentView : ReactiveUserControl + private readonly Rectangle _keyframeDragAnchor; + private double _dragOffset; + + public MainSegmentView() { - private readonly Rectangle _keyframeDragAnchor; - private double _dragOffset; + InitializeComponent(); + _keyframeDragAnchor = this.Get("KeyframeDragAnchor"); + } - public MainSegmentView() - { - InitializeComponent(); - _keyframeDragAnchor = this.Get("KeyframeDragAnchor"); - } + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } + private void KeyframeDragAnchor_OnPointerPressed(object? sender, PointerPressedEventArgs e) + { + if (ViewModel == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) + return; + e.Pointer.Capture(_keyframeDragAnchor); - private void KeyframeDragAnchor_OnPointerPressed(object? sender, PointerPressedEventArgs e) - { - if (ViewModel == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) - return; - e.Pointer.Capture(_keyframeDragAnchor); + _dragOffset = ViewModel.Width - e.GetCurrentPoint(this).Position.X; + ViewModel.StartResize(); + } - _dragOffset = ViewModel.Width - e.GetCurrentPoint(this).Position.X; - ViewModel.StartResize(); - } + private void KeyframeDragAnchor_OnPointerMoved(object? sender, PointerEventArgs e) + { + if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) + return; + ViewModel.UpdateResize(e.GetCurrentPoint(this).Position.X + _dragOffset); + } - private void KeyframeDragAnchor_OnPointerMoved(object? sender, PointerEventArgs e) - { - if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) - return; - ViewModel.UpdateResize(e.GetCurrentPoint(this).Position.X + _dragOffset); - } + private void KeyframeDragAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e) + { + if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) + return; + e.Pointer.Capture(null); + ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset); + } - private void KeyframeDragAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e) - { - if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) - return; - e.Pointer.Capture(null); - ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset); - } + private void KeyframeDragStartAnchor_OnPointerPressed(object? sender, PointerPressedEventArgs e) + { + } - private void KeyframeDragStartAnchor_OnPointerPressed(object? sender, PointerPressedEventArgs e) - { - } + private void KeyframeDragStartAnchor_OnPointerMoved(object? sender, PointerEventArgs e) + { + } - private void KeyframeDragStartAnchor_OnPointerMoved(object? sender, PointerEventArgs e) - { - } - - private void KeyframeDragStartAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e) - { - } + private void KeyframeDragStartAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e) + { } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/Segment.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/Segment.axaml index 6502c23be..3ef9f2586 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/Segment.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/Segment.axaml @@ -6,23 +6,22 @@ - + - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentView.axaml index 8ec723260..527a04d72 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentView.axaml @@ -2,7 +2,6 @@ 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:system="clr-namespace:System;assembly=System.Runtime" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:segments="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="18" @@ -49,7 +48,7 @@ PointerPressed="KeyframeDragAnchor_OnPointerPressed" PointerMoved="KeyframeDragAnchor_OnPointerMoved" PointerReleased="KeyframeDragAnchor_OnPointerReleased" - ToolTip.Tip="{CompiledBinding EndTimestamp}"/> + ToolTip.Tip="{CompiledBinding EndTimestamp}" /> diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentView.axaml.cs index 234acb2de..308d30f8f 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentView.axaml.cs @@ -4,47 +4,46 @@ using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments +namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments; + +public class StartSegmentView : ReactiveUserControl { - public partial class StartSegmentView : ReactiveUserControl + private readonly Rectangle _keyframeDragAnchor; + private double _dragOffset; + + public StartSegmentView() { - private readonly Rectangle _keyframeDragAnchor; - private double _dragOffset; + InitializeComponent(); + _keyframeDragAnchor = this.Get("KeyframeDragAnchor"); + } - public StartSegmentView() - { - InitializeComponent(); - _keyframeDragAnchor = this.Get("KeyframeDragAnchor"); - } + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } + private void KeyframeDragAnchor_OnPointerPressed(object? sender, PointerPressedEventArgs e) + { + if (ViewModel == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) + return; + e.Pointer.Capture(_keyframeDragAnchor); - private void KeyframeDragAnchor_OnPointerPressed(object? sender, PointerPressedEventArgs e) - { - if (ViewModel == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) - return; - e.Pointer.Capture(_keyframeDragAnchor); + _dragOffset = ViewModel.Width - e.GetCurrentPoint(this).Position.X; + ViewModel.StartResize(); + } - _dragOffset = ViewModel.Width - e.GetCurrentPoint(this).Position.X; - ViewModel.StartResize(); - } + private void KeyframeDragAnchor_OnPointerMoved(object? sender, PointerEventArgs e) + { + if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) + return; + ViewModel.UpdateResize(e.GetCurrentPoint(this).Position.X + _dragOffset); + } - private void KeyframeDragAnchor_OnPointerMoved(object? sender, PointerEventArgs e) - { - if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) - return; - ViewModel.UpdateResize(e.GetCurrentPoint(this).Position.X + _dragOffset); - } - - private void KeyframeDragAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e) - { - if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) - return; - e.Pointer.Capture(null); - ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset); - } + private void KeyframeDragAnchor_OnPointerReleased(object? sender, PointerReleasedEventArgs e) + { + if (ViewModel == null || !ReferenceEquals(e.Pointer.Captured, _keyframeDragAnchor)) + return; + e.Pointer.Capture(null); + ViewModel.FinishResize(e.GetCurrentPoint(this).Position.X + _dragOffset); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentViewModel.cs index 926466e43..58329f454 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/StartSegmentViewModel.cs @@ -1,12 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Reactive.Linq; using Artemis.Core; using Artemis.UI.Shared.Services.ProfileEditor; using Artemis.UI.Shared.Services.ProfileEditor.Commands; using Avalonia.Controls.Mixins; -using Castle.DynamicProxy.Generators; using ReactiveUI; namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments; @@ -14,13 +11,13 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments; public class StartSegmentViewModel : TimelineSegmentViewModel { private readonly IProfileEditorService _profileEditorService; - private RenderProfileElement? _profileElement; - private int _pixelsPerSecond; - private TimeSpan _time; + private readonly ObservableAsPropertyHelper _width; private ObservableAsPropertyHelper? _end; private ObservableAsPropertyHelper? _endTimestamp; - private readonly ObservableAsPropertyHelper _width; private TimeSpan _initialLength; + private int _pixelsPerSecond; + private RenderProfileElement? _profileElement; + private TimeSpan _time; public StartSegmentViewModel(IProfileEditorService profileEditorService) : base(profileEditorService) { @@ -52,6 +49,7 @@ public class StartSegmentViewModel : TimelineSegmentViewModel public override double StartX => 0; public override TimeSpan End => _profileElement?.Timeline.StartSegmentEndPosition ?? TimeSpan.Zero; public override double EndX => _end?.Value ?? 0; + public override TimeSpan Length { get => _profileElement?.Timeline.StartSegmentLength ?? TimeSpan.Zero; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/TimelineSegmentViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/TimelineSegmentViewModel.cs index e60369967..4f9a1a422 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/TimelineSegmentViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/TimelineSegmentViewModel.cs @@ -15,14 +15,14 @@ public abstract class TimelineSegmentViewModel : ActivatableViewModelBase { private static readonly TimeSpan NewSegmentLength = TimeSpan.FromSeconds(2); private readonly IProfileEditorService _profileEditorService; - private RenderProfileElement? _profileElement; + private TimeSpan _initialLength; + private readonly Dictionary _originalKeyframePositions = new(); private int _pixelsPerSecond; - private Dictionary _originalKeyframePositions = new(); + private RenderProfileElement? _profileElement; + private ObservableAsPropertyHelper? _showAddEnd; + private ObservableAsPropertyHelper? _showAddMain; private ObservableAsPropertyHelper? _showAddStart; - private ObservableAsPropertyHelper? _showAddMain; - private ObservableAsPropertyHelper? _showAddEnd; - private TimeSpan _initialLength; protected TimelineSegmentViewModel(IProfileEditorService profileEditorService) { @@ -136,8 +136,10 @@ public abstract class TimelineSegmentViewModel : ActivatableViewModelBase // Delete keyframes in the segment foreach (ILayerPropertyKeyframe layerPropertyKeyframe in keyframes) + { if (layerPropertyKeyframe.Position > Start && layerPropertyKeyframe.Position <= End) _profileEditorService.ExecuteCommand(new DeleteKeyframe(layerPropertyKeyframe)); + } // Move keyframes after the segment forwards ShiftKeyframes(keyframes.Where(s => s.Position > End), new TimeSpan(Length.Ticks * -1)); diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelineView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelineView.axaml index 9986bc9a9..b67715de4 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelineView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelineView.axaml @@ -8,13 +8,11 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Timeline.TimelineView" x:DataType="timeline:TimelineViewModel"> - - 28 - 29 - + + - + @@ -23,8 +21,8 @@ - - + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelineViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelineViewModel.cs index ccd0aa2b7..572a32eb8 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelineViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelineViewModel.cs @@ -3,12 +3,10 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive.Linq; -using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes; using Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments; using Artemis.UI.Shared; using Artemis.UI.Shared.Services.ProfileEditor; -using Artemis.UI.Shared.Services.ProfileEditor.Commands; using Avalonia.Controls.Mixins; using ReactiveUI; @@ -18,13 +16,13 @@ public class TimelineViewModel : ActivatableViewModelBase { private readonly IProfileEditorService _profileEditorService; private ObservableAsPropertyHelper? _caretPosition; - private ObservableAsPropertyHelper? _pixelsPerSecond; - private List? _moveKeyframes; private ObservableAsPropertyHelper _minWidth; + private List? _moveKeyframes; + private ObservableAsPropertyHelper? _pixelsPerSecond; public TimelineViewModel(ObservableCollection propertyGroupViewModels, StartSegmentViewModel startSegmentViewModel, - MainSegmentViewModel mainSegmentViewModel, + MainSegmentViewModel mainSegmentViewModel, EndSegmentViewModel endSegmentViewModel, IProfileEditorService profileEditorService) { @@ -141,8 +139,10 @@ public class TimelineViewModel : ActivatableViewModelBase public void DuplicateKeyframes(ITimelineKeyframeViewModel? source = null) { - if (source is { IsSelected: false }) + if (source is {IsSelected: false}) + { source.Delete(); + } else { List keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList(); @@ -154,8 +154,10 @@ public class TimelineViewModel : ActivatableViewModelBase public void CopyKeyframes(ITimelineKeyframeViewModel? source = null) { - if (source is { IsSelected: false }) + if (source is {IsSelected: false}) + { source.Copy(); + } else { List keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList(); @@ -167,8 +169,10 @@ public class TimelineViewModel : ActivatableViewModelBase public void PasteKeyframes(ITimelineKeyframeViewModel? source = null) { - if (source is { IsSelected: false }) + if (source is {IsSelected: false}) + { source.Paste(); + } else { List keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList(); @@ -181,7 +185,9 @@ public class TimelineViewModel : ActivatableViewModelBase public void DeleteKeyframes(ITimelineKeyframeViewModel? source = null) { if (source is {IsSelected: false}) + { source.Delete(); + } else { List keyframes = PropertyGroupViewModels.SelectMany(g => g.GetAllKeyframeViewModels(true)).Where(k => k.IsSelected).ToList(); diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameView.axaml index 81414eae7..744838e50 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameView.axaml @@ -10,6 +10,6 @@ - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameViewModel.cs index fd180e95c..776928ce5 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameViewModel.cs @@ -7,39 +7,38 @@ using FluentAvalonia.UI.Controls; using ReactiveUI; using ReactiveUI.Validation.Extensions; -namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs +namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs; + +public class LayerEffectRenameViewModel : ContentDialogViewModelBase { - public class LayerEffectRenameViewModel : ContentDialogViewModelBase + private readonly BaseLayerEffect _layerEffect; + private readonly IProfileEditorService _profileEditorService; + private string? _layerEffectName; + + public LayerEffectRenameViewModel(IProfileEditorService profileEditorService, BaseLayerEffect layerEffect) { - private readonly IProfileEditorService _profileEditorService; - private readonly BaseLayerEffect _layerEffect; - private string? _layerEffectName; + _profileEditorService = profileEditorService; + _layerEffect = layerEffect; + _layerEffectName = layerEffect.Name; - public LayerEffectRenameViewModel(IProfileEditorService profileEditorService, BaseLayerEffect layerEffect) - { - _profileEditorService = profileEditorService; - _layerEffect = layerEffect; - _layerEffectName = layerEffect.Name; + Confirm = ReactiveCommand.Create(ExecuteConfirm, ValidationContext.Valid); + this.ValidationRule(vm => vm.LayerEffectName, categoryName => !string.IsNullOrWhiteSpace(categoryName), "You must specify a valid name"); + } - Confirm = ReactiveCommand.Create(ExecuteConfirm, ValidationContext.Valid); - this.ValidationRule(vm => vm.LayerEffectName, categoryName => !string.IsNullOrWhiteSpace(categoryName), "You must specify a valid name"); - } + public string? LayerEffectName + { + get => _layerEffectName; + set => RaiseAndSetIfChanged(ref _layerEffectName, value); + } - public string? LayerEffectName - { - get => _layerEffectName; - set => this.RaiseAndSetIfChanged(ref _layerEffectName, value); - } + public ReactiveCommand Confirm { get; } - public ReactiveCommand Confirm { get; } + private void ExecuteConfirm() + { + if (LayerEffectName == null) + return; - private void ExecuteConfirm() - { - if (LayerEffectName == null) - return; - - _profileEditorService.ExecuteCommand(new RenameLayerEffect(_layerEffect, LayerEffectName)); - ContentDialog?.Hide(ContentDialogResult.Primary); - } + _profileEditorService.ExecuteCommand(new RenameLayerEffect(_layerEffect, LayerEffectName)); + ContentDialog?.Hide(ContentDialogResult.Primary); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ITreePropertyViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ITreePropertyViewModel.cs index a4a6f8f3c..b91eca4e7 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ITreePropertyViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ITreePropertyViewModel.cs @@ -1,5 +1,4 @@ -using System.Reactive; -using Artemis.Core; +using Artemis.Core; using ReactiveUI; namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupView.axaml index 71bdfb6e8..253913734 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupView.axaml @@ -71,14 +71,14 @@ Height="29" ColumnDefinitions="Auto,Auto,Auto,*"> + Icon="{CompiledBinding LayerBrush.Descriptor.Icon}" + Width="16" + Height="16" + Margin="0 0 5 0" /> - Brush - + Brush - PropertyGroupViewModel.LayerEffect; public LayerPropertyGroupType GroupType { get; private set; } public ObservableCollection? Children => PropertyGroupViewModel.IsExpanded ? PropertyGroupViewModel.Children : null; - + public ReactiveCommand OpenBrushSettings { get; } public ReactiveCommand OpenEffectSettings { get; } public ReactiveCommand RenameEffect { get; } public ReactiveCommand DeleteEffect { get; } + public double GetDepth() + { + int depth = 0; + LayerPropertyGroup? current = LayerPropertyGroup.Parent; + while (current != null) + { + depth++; + current = current.Parent; + } + + return depth; + } + private async Task ExecuteOpenBrushSettings() { if (LayerBrush?.ConfigurationDialog is not LayerBrushConfigurationDialog configurationViewModel) @@ -145,19 +158,6 @@ public class TreeGroupViewModel : ActivatableViewModelBase _profileEditorService.ExecuteCommand(new RemoveLayerEffect(LayerEffect)); } - public double GetDepth() - { - int depth = 0; - LayerPropertyGroup? current = LayerPropertyGroup.Parent; - while (current != null) - { - depth++; - current = current.Parent; - } - - return depth; - } - private void CloseViewModels() { _effectConfigurationWindowViewModel?.Close(null); diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyView.axaml index dc5def2ac..64b32bf15 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyView.axaml @@ -4,7 +4,6 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:converters="clr-namespace:Artemis.UI.Converters" - xmlns:sharedConverters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared" xmlns:tree="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Tree" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Tree.TreePropertyView" @@ -39,7 +38,7 @@ + Content="{Binding PropertyInputViewModel}" /> - : ActivatableViewModelBase, ITreePropertyViewModel { private readonly IProfileEditorService _profileEditorService; - private TimeSpan _time; - private ObservableAsPropertyHelper? _isCurrentlySelected; private ObservableAsPropertyHelper? _dataBindingEnabled; + private ObservableAsPropertyHelper? _isCurrentlySelected; + private TimeSpan _time; public TreePropertyViewModel(LayerProperty layerProperty, PropertyViewModel propertyViewModel, IProfileEditorService profileEditorService, IPropertyInputService propertyInputService) { @@ -40,7 +40,6 @@ internal class TreePropertyViewModel : ActivatableViewModelBase, ITreePropert } public bool IsCurrentlySelected => _isCurrentlySelected?.Value ?? false; - public bool DataBindingEnabled => _dataBindingEnabled?.Value ?? false; public LayerProperty LayerProperty { get; } public PropertyViewModel PropertyViewModel { get; } public PropertyInputViewModel? PropertyInputViewModel { get; } @@ -65,6 +64,8 @@ internal class TreePropertyViewModel : ActivatableViewModelBase, ITreePropert _profileEditorService.ExecuteCommand(new ResetLayerProperty(LayerProperty)); } + public bool DataBindingEnabled => _dataBindingEnabled?.Value ?? false; + public ILayerProperty BaseLayerProperty => LayerProperty; public double GetDepth() diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/BrushConfigurationWindowViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/BrushConfigurationWindowViewModel.cs index 55bce2cd3..4a51d9f74 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/BrushConfigurationWindowViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/BrushConfigurationWindowViewModel.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using Artemis.UI.Shared; using Artemis.UI.Shared.LayerBrushes; -using Avalonia.Threading; namespace Artemis.UI.Screens.ProfileEditor.Properties.Windows; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/EffectConfigurationWindowViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/EffectConfigurationWindowViewModel.cs index fa2b55aaa..dd3778036 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/EffectConfigurationWindowViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/EffectConfigurationWindowViewModel.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using Artemis.UI.Shared; using Artemis.UI.Shared.LayerEffects; -using Avalonia.Threading; namespace Artemis.UI.Screens.ProfileEditor.Properties.Windows; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/StatusBar/StatusBarView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/StatusBar/StatusBarView.axaml index 92ab2bf54..4ee09fed8 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/StatusBar/StatusBarView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/StatusBar/StatusBarView.axaml @@ -8,13 +8,13 @@ x:Class="Artemis.UI.Screens.ProfileEditor.StatusBar.StatusBarView"> - - - - + + + + @@ -103,7 +102,7 @@ Press F5 to switch between editor mode and normal mode. Auto-switching can be disabled in the run menu. - + @@ -127,7 +126,7 @@ - + diff --git a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorView.axaml.cs index 1a68b5369..c11d7da7c 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorView.axaml.cs @@ -2,23 +2,21 @@ using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.ProfileEditor +namespace Artemis.UI.Screens.ProfileEditor; + +public class ProfileEditorView : ReactiveUserControl { - public class ProfileEditorView : ReactiveUserControl + public ProfileEditorView() { - public ProfileEditorView() - { - InitializeComponent(); - } + InitializeComponent(); + } - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } - private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e) - { - - } + private void MenuItem_OnSubmenuOpened(object? sender, RoutedEventArgs e) + { } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs index a63947d04..fc11ab8dd 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs @@ -97,5 +97,6 @@ public class ProfileEditorViewModel : MainScreenViewModel private void ExecuteToggleAutoSuspend() { + // TODO } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs index 90e3186a0..296b496f9 100644 --- a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs @@ -151,18 +151,9 @@ namespace Artemis.UI.Screens.Sidebar if (!await _windowService.ShowConfirmContentDialog("Delete profile", "Are you sure you want to permanently delete this profile?")) return; - try - { - if (_profileConfiguration.IsBeingEdited) - _profileEditorService.ChangeCurrentProfileConfiguration(null); - _profileService.RemoveProfileConfiguration(_profileConfiguration); - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - + if (_profileConfiguration.IsBeingEdited) + _profileEditorService.ChangeCurrentProfileConfiguration(null); + _profileService.RemoveProfileConfiguration(_profileConfiguration); Close(_profileConfiguration); } diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml index 530396d61..d93326e33 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml +++ b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml @@ -5,7 +5,8 @@ xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:local="clr-namespace:Artemis.UI.Screens.Sidebar" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Artemis.UI.Screens.Sidebar.SidebarCategoryView"> + x:Class="Artemis.UI.Screens.Sidebar.SidebarCategoryView" + x:DataType="local:SidebarCategoryViewModel"> + - + - @@ -61,7 +66,7 @@ + Command="{CompiledBinding EditCategory}" + Margin="0 0 2 0"> - - - + diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml.cs b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml.cs index 6e627a580..19afda3ed 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml.cs @@ -1,4 +1,5 @@ -using Avalonia.Input; +using System; +using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; @@ -18,8 +19,7 @@ namespace Artemis.UI.Screens.Sidebar private void Title_OnPointerPressed(object? sender, PointerPressedEventArgs e) { - if (ViewModel != null) - ViewModel.ShowItems = !ViewModel.ShowItems; + ViewModel?.ToggleCollapsed.Execute().Subscribe(); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs index 715fbe791..ebb6df9bf 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs @@ -1,15 +1,19 @@ using System; using System.Collections.ObjectModel; using System.Linq; +using System.Reactive; using System.Reactive.Disposables; +using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; +using Artemis.Core.Events; using Artemis.Core.Services; using Artemis.UI.Ninject.Factories; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Artemis.UI.Shared.Services.ProfileEditor; +using DynamicData; using ReactiveUI; namespace Artemis.UI.Screens.Sidebar @@ -21,6 +25,8 @@ namespace Artemis.UI.Screens.Sidebar private readonly ISidebarVmFactory _vmFactory; private readonly IWindowService _windowService; private SidebarProfileConfigurationViewModel? _selectedProfileConfiguration; + private ObservableAsPropertyHelper? _isCollapsed; + private ObservableAsPropertyHelper? _isSuspended; public SidebarCategoryViewModel(SidebarViewModel sidebarViewModel, ProfileCategory profileCategory, IProfileService profileService, IWindowService windowService, IProfileEditorService profileEditorService, ISidebarVmFactory vmFactory) @@ -31,24 +37,59 @@ namespace Artemis.UI.Screens.Sidebar _vmFactory = vmFactory; ProfileCategory = profileCategory; + SourceCache profileConfigurations = new(t => t.ProfileId); - if (ShowItems) - CreateProfileViewModels(); + // Only show items when not collapsed + IObservable> profileConfigurationsFilter = this.WhenAnyValue(vm => vm.IsCollapsed).Select(b => new Func(_ => !b)); + profileConfigurations.Connect() + .SortBy(c => c.Order) + .Filter(profileConfigurationsFilter) + .Transform(c => _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, c)) + .Bind(out ReadOnlyObservableCollection profileConfigurationViewModels) + .Subscribe(); + ProfileConfigurations = profileConfigurationViewModels; - this.WhenActivated(disposables => + ToggleCollapsed = ReactiveCommand.Create(ExecuteToggleCollapsed); + ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended); + AddProfile = ReactiveCommand.CreateFromTask(ExecuteAddProfile); + EditCategory = ReactiveCommand.CreateFromTask(ExecuteEditCategory); + + this.WhenActivated(d => { - profileEditorService.ProfileConfiguration - .Subscribe(p => SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(c => ReferenceEquals(c.ProfileConfiguration, p))) - .DisposeWith(disposables); - this.WhenAnyValue(vm => vm.SelectedProfileConfiguration) - .WhereNotNull() - .Subscribe(s => profileEditorService.ChangeCurrentProfileConfiguration(s.ProfileConfiguration)); + // Update the list of profiles whenever the category fires events + Observable.FromEventPattern(x => profileCategory.ProfileConfigurationAdded += x, x => profileCategory.ProfileConfigurationAdded -= x) + .Subscribe(e => profileConfigurations.AddOrUpdate(e.EventArgs.ProfileConfiguration)) + .DisposeWith(d); + Observable.FromEventPattern(x => profileCategory.ProfileConfigurationRemoved += x, x => profileCategory.ProfileConfigurationRemoved -= x) + .Subscribe(e => profileConfigurations.Remove(e.EventArgs.ProfileConfiguration)) + .DisposeWith(d); + + profileEditorService.ProfileConfiguration.Subscribe(p => SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(c => ReferenceEquals(c.ProfileConfiguration, p))) + .DisposeWith(d); + + _isCollapsed = ProfileCategory.WhenAnyValue(vm => vm.IsCollapsed).ToProperty(this, vm => vm.IsCollapsed).DisposeWith(d); + _isSuspended = ProfileCategory.WhenAnyValue(vm => vm.IsSuspended).ToProperty(this, vm => vm.IsSuspended).DisposeWith(d); + + // Change the current profile configuration when a new one is selected + this.WhenAnyValue(vm => vm.SelectedProfileConfiguration).WhereNotNull().Subscribe(s => profileEditorService.ChangeCurrentProfileConfiguration(s.ProfileConfiguration)); + }); + + profileConfigurations.Edit(updater => + { + foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations) + updater.AddOrUpdate(profileConfiguration); }); } + public ReactiveCommand ToggleCollapsed { get; } + public ReactiveCommand ToggleSuspended { get; } + public ReactiveCommand AddProfile { get; } + public ReactiveCommand EditCategory { get; } public ProfileCategory ProfileCategory { get; } + public ReadOnlyObservableCollection ProfileConfigurations { get; } - public ObservableCollection ProfileConfigurations { get; } = new(); + public bool IsCollapsed => _isCollapsed?.Value ?? false; + public bool IsSuspended => _isSuspended?.Value ?? false; public SidebarProfileConfigurationViewModel? SelectedProfileConfiguration { @@ -56,34 +97,7 @@ namespace Artemis.UI.Screens.Sidebar set => RaiseAndSetIfChanged(ref _selectedProfileConfiguration, value); } - public bool ShowItems - { - get => !ProfileCategory.IsCollapsed; - set - { - ProfileCategory.IsCollapsed = !value; - if (ProfileCategory.IsCollapsed) - ProfileConfigurations.Clear(); - else - CreateProfileViewModels(); - _profileService.SaveProfileCategory(ProfileCategory); - - this.RaisePropertyChanged(nameof(ShowItems)); - } - } - - public bool IsSuspended - { - get => ProfileCategory.IsSuspended; - set - { - ProfileCategory.IsSuspended = value; - this.RaisePropertyChanged(nameof(IsSuspended)); - _profileService.SaveProfileCategory(ProfileCategory); - } - } - - public async Task EditCategory() + private async Task ExecuteEditCategory() { await _windowService.CreateContentDialog() .WithTitle("Edit category") @@ -97,7 +111,7 @@ namespace Artemis.UI.Screens.Sidebar _sidebarViewModel.UpdateProfileCategories(); } - public async Task AddProfile() + private async Task ExecuteAddProfile() { ProfileConfiguration? result = await _windowService.ShowDialogAsync( ("profileCategory", ProfileCategory), @@ -106,18 +120,20 @@ namespace Artemis.UI.Screens.Sidebar if (result != null) { SidebarProfileConfigurationViewModel viewModel = _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, result); - ProfileConfigurations.Insert(0, viewModel); SelectedProfileConfiguration = viewModel; } } - private void CreateProfileViewModels() + private void ExecuteToggleCollapsed() { - ProfileConfigurations.Clear(); - foreach (ProfileConfiguration profileConfiguration in ProfileCategory.ProfileConfigurations.OrderBy(p => p.Order)) - ProfileConfigurations.Add(_vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, profileConfiguration)); + ProfileCategory.IsCollapsed = !ProfileCategory.IsCollapsed; + _profileService.SaveProfileCategory(ProfileCategory); + } - SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(i => i.ProfileConfiguration.IsBeingEdited); + private void ExecuteToggleSuspended() + { + ProfileCategory.IsSuspended = !ProfileCategory.IsSuspended; + _profileService.SaveProfileCategory(ProfileCategory); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationView.axaml b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationView.axaml index 86f6e3b05..72953939d 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationView.axaml +++ b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationView.axaml @@ -69,11 +69,11 @@ + x:Name="ProfileIcon" + VerticalAlignment="Center" + ConfigurationIcon="{CompiledBinding ProfileConfiguration.Icon}" + Width="20" + Height="20" /> + HorizontalAlignment="Right" + Margin="0 0 2 0"> - - - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs index ccc8ea4dd..293679476 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs @@ -26,31 +26,22 @@ namespace Artemis.UI.Screens.Sidebar ProfileConfiguration = profileConfiguration; EditProfile = ReactiveCommand.CreateFromTask(ExecuteEditProfile); + ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended); this.WhenActivated(d => { - _isSuspended = ProfileConfiguration.WhenAnyValue(c => c.IsSuspended) - .ToProperty(this, vm => vm.IsSuspended) - .DisposeWith(d); + _isSuspended = ProfileConfiguration.WhenAnyValue(c => c.IsSuspended).ToProperty(this, vm => vm.IsSuspended).DisposeWith(d); }); _profileService.LoadProfileConfigurationIcon(ProfileConfiguration); } + public ReactiveCommand EditProfile { get; } + public ReactiveCommand ToggleSuspended { get; } - public bool IsProfileActive => ProfileConfiguration.Profile != null; + public bool IsSuspended => _isSuspended?.Value ?? false; - public bool IsSuspended - { - get => _isSuspended?.Value ?? false; - set - { - ProfileConfiguration.IsSuspended = value; - _profileService.SaveProfileCategory(ProfileConfiguration.Category); - } - } - - public async Task ExecuteEditProfile() + private async Task ExecuteEditProfile() { ProfileConfiguration? edited = await _windowService.ShowDialogAsync( ("profileCategory", ProfileConfiguration.Category), @@ -60,5 +51,11 @@ namespace Artemis.UI.Screens.Sidebar if (edited != null) _sidebarViewModel.UpdateProfileCategories(); } + + private void ExecuteToggleSuspended() + { + ProfileConfiguration.IsSuspended = !ProfileConfiguration.IsSuspended; + _profileService.SaveProfileCategory(ProfileConfiguration.Category); + } } } \ No newline at end of file