mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Scripting - Add confirm dialog when discarding changes
Editor - Fix missing repeat mode button Editor - Auto-save 1 sec after last change General UI - Fix main window drag handle
This commit is contained in:
parent
e3907e6a76
commit
311bdee8da
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reactive;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -64,6 +65,19 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
PixelsPerSecond = _pixelsPerSecondSubject.AsObservable();
|
PixelsPerSecond = _pixelsPerSecondSubject.AsObservable();
|
||||||
Tools = tools;
|
Tools = tools;
|
||||||
SelectedKeyframes = selectedKeyframes;
|
SelectedKeyframes = selectedKeyframes;
|
||||||
|
|
||||||
|
// Observe executing, undoing and redoing commands and run the auto-save after 1 second
|
||||||
|
History.Select(h => h?.Execute ?? Observable.Never<Unit>())
|
||||||
|
.Switch()
|
||||||
|
.Merge(History.Select(h => h?.Undo ?? Observable.Never<IProfileEditorCommand?>())
|
||||||
|
.Switch()
|
||||||
|
.Select(_ => Unit.Default))
|
||||||
|
.Merge(History.Select(h => h?.Redo ?? Observable.Never<IProfileEditorCommand?>())
|
||||||
|
.Switch()
|
||||||
|
.Select(_ => Unit.Default))
|
||||||
|
.Throttle(TimeSpan.FromSeconds(1))
|
||||||
|
.SelectMany(async _ => await AutoSaveProfileAsync())
|
||||||
|
.Subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IObservable<ProfileConfiguration?> ProfileConfiguration { get; }
|
public IObservable<ProfileConfiguration?> ProfileConfiguration { get; }
|
||||||
@ -425,6 +439,22 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
return newHistory;
|
return newHistory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Unit> AutoSaveProfileAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await SaveProfileAsync();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_windowService.ShowExceptionDialog("Failed to auto-save profile", e);
|
||||||
|
_logger.Error(e, "Failed to auto-save profile");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Unit.Default;
|
||||||
|
}
|
||||||
|
|
||||||
private void Tick(TimeSpan time)
|
private void Tick(TimeSpan time)
|
||||||
{
|
{
|
||||||
if (_profileConfigurationSubject.Value?.Profile == null || _suspendedEditingSubject.Value)
|
if (_profileConfigurationSubject.Value?.Profile == null || _suspendedEditingSubject.Value)
|
||||||
|
|||||||
@ -22,14 +22,13 @@ namespace Artemis.UI.Windows
|
|||||||
|
|
||||||
public override void OnFrameworkInitializationCompleted()
|
public override void OnFrameworkInitializationCompleted()
|
||||||
{
|
{
|
||||||
ArtemisBootstrapper.Initialize();
|
if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
return;
|
||||||
|
|
||||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
ArtemisBootstrapper.Initialize();
|
||||||
{
|
|
||||||
_applicationStateManager = new ApplicationStateManager(_kernel!, desktop.Args);
|
_applicationStateManager = new ApplicationStateManager(_kernel!, desktop.Args);
|
||||||
RegisterProviders(_kernel!);
|
RegisterProviders(_kernel!);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void RegisterProviders(StandardKernel standardKernel)
|
private void RegisterProviders(StandardKernel standardKernel)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
Icon="/Assets/Images/Logo/application.ico"
|
Icon="/Assets/Images/Logo/application.ico"
|
||||||
Title="Artemis 2.0">
|
Title="Artemis 2.0">
|
||||||
<Panel Name="RootPanel">
|
<Panel Name="RootPanel">
|
||||||
|
<Border Name="DragHandle" Background="Transparent" Height="40" HorizontalAlignment="Stretch" VerticalAlignment="Top"/>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<ContentControl Name="SidebarContentControl" Content="{Binding SidebarViewModel}" DockPanel.Dock="Left" Width="240">
|
<ContentControl Name="SidebarContentControl" Content="{Binding SidebarViewModel}" DockPanel.Dock="Left" Width="240">
|
||||||
<ContentControl.Transitions>
|
<ContentControl.Transitions>
|
||||||
@ -16,7 +17,7 @@
|
|||||||
</Transitions>
|
</Transitions>
|
||||||
</ContentControl.Transitions>
|
</ContentControl.Transitions>
|
||||||
</ContentControl>
|
</ContentControl>
|
||||||
<Border Background="Transparent" Name="TitleBar" DockPanel.Dock="Top">
|
<Border Name="TitleBar" DockPanel.Dock="Top">
|
||||||
<ContentControl Content="{Binding TitleBarViewModel}" />
|
<ContentControl Content="{Binding TitleBarViewModel}" />
|
||||||
</Border>
|
</Border>
|
||||||
<ContentControl Content="{Binding}" />
|
<ContentControl Content="{Binding}" />
|
||||||
|
|||||||
@ -41,7 +41,7 @@ namespace Artemis.UI
|
|||||||
if (coreAppTitleBar.TitleBar != null)
|
if (coreAppTitleBar.TitleBar != null)
|
||||||
{
|
{
|
||||||
coreAppTitleBar.TitleBar.ExtendViewIntoTitleBar = true;
|
coreAppTitleBar.TitleBar.ExtendViewIntoTitleBar = true;
|
||||||
SetTitleBar(this.Get<Border>("TitleBar"));
|
SetTitleBar(this.Get<Border>("DragHandle"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -132,6 +132,7 @@ public class MenuBarViewModel : ActivatableViewModelBase
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
await _windowService.ShowDialogAsync<ScriptsDialogViewModel, object?>(("profile", ProfileConfiguration.Profile));
|
await _windowService.ShowDialogAsync<ScriptsDialogViewModel, object?>(("profile", ProfileConfiguration.Profile));
|
||||||
|
await _profileEditorService.SaveProfileAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExecuteAdaptProfile()
|
private async Task ExecuteAdaptProfile()
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
<avalonia:MaterialIcon Kind="SkipNext" />
|
<avalonia:MaterialIcon Kind="SkipNext" />
|
||||||
</Button>
|
</Button>
|
||||||
<ToggleButton Classes="icon-button icon-button-large"
|
<ToggleButton Classes="icon-button icon-button-large"
|
||||||
IsChecked="{CompiledBinding Repeating}"
|
IsChecked="{CompiledBinding Repeating, Mode=OneWay}"
|
||||||
Focusable="False"
|
Focusable="False"
|
||||||
Command="{CompiledBinding CycleRepeating}">
|
Command="{CompiledBinding CycleRepeating}">
|
||||||
<ToolTip.Tip>
|
<ToolTip.Tip>
|
||||||
|
|||||||
@ -28,6 +28,7 @@ public class PlaybackViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
|
_repeatTimeline = true;
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
@ -142,6 +143,7 @@ public class PlaybackViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
RepeatTimeline = false;
|
RepeatTimeline = false;
|
||||||
RepeatSegment = true;
|
RepeatSegment = true;
|
||||||
|
this.RaisePropertyChanged(nameof(Repeating));
|
||||||
}
|
}
|
||||||
else if (RepeatSegment)
|
else if (RepeatSegment)
|
||||||
{
|
{
|
||||||
@ -149,6 +151,7 @@ public class PlaybackViewModel : ActivatableViewModelBase
|
|||||||
RepeatSegment = false;
|
RepeatSegment = false;
|
||||||
Repeating = false;
|
Repeating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimeSpan GetCurrentSegmentStart()
|
private TimeSpan GetCurrentSegmentStart()
|
||||||
|
|||||||
@ -6,6 +6,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Windows;
|
|||||||
|
|
||||||
public class BrushConfigurationWindowView : ReactiveCoreWindow<BrushConfigurationWindowViewModel>
|
public class BrushConfigurationWindowView : ReactiveCoreWindow<BrushConfigurationWindowViewModel>
|
||||||
{
|
{
|
||||||
|
private bool _canClose;
|
||||||
|
|
||||||
public BrushConfigurationWindowView()
|
public BrushConfigurationWindowView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -22,9 +24,14 @@ public class BrushConfigurationWindowView : ReactiveCoreWindow<BrushConfiguratio
|
|||||||
|
|
||||||
private async void OnClosing(object? sender, CancelEventArgs e)
|
private async void OnClosing(object? sender, CancelEventArgs e)
|
||||||
{
|
{
|
||||||
if (ViewModel == null)
|
if (_canClose)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
e.Cancel = !await ViewModel.CanClose();
|
e.Cancel = true;
|
||||||
|
if (ViewModel == null || await ViewModel.CanClose())
|
||||||
|
{
|
||||||
|
_canClose = true;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,6 +6,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Windows;
|
|||||||
|
|
||||||
public class EffectConfigurationWindowView : ReactiveCoreWindow<EffectConfigurationWindowViewModel>
|
public class EffectConfigurationWindowView : ReactiveCoreWindow<EffectConfigurationWindowViewModel>
|
||||||
{
|
{
|
||||||
|
private bool _canClose;
|
||||||
|
|
||||||
public EffectConfigurationWindowView()
|
public EffectConfigurationWindowView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -22,9 +24,14 @@ public class EffectConfigurationWindowView : ReactiveCoreWindow<EffectConfigurat
|
|||||||
|
|
||||||
private async void OnClosing(object? sender, CancelEventArgs e)
|
private async void OnClosing(object? sender, CancelEventArgs e)
|
||||||
{
|
{
|
||||||
if (ViewModel == null)
|
if (_canClose)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
e.Cancel = !await ViewModel.CanClose();
|
e.Cancel = true;
|
||||||
|
if (ViewModel == null || await ViewModel.CanClose())
|
||||||
|
{
|
||||||
|
_canClose = true;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9,9 +9,11 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Scripting.ScriptsDialogView"
|
x:Class="Artemis.UI.Screens.Scripting.ScriptsDialogView"
|
||||||
x:DataType="scripting:ScriptsDialogViewModel"
|
x:DataType="scripting:ScriptsDialogViewModel"
|
||||||
Title="ScriptsDialogView">
|
Title="Artemis | Scripts"
|
||||||
|
Width="1200"
|
||||||
|
Height="750">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<ScrollViewer DockPanel.Dock="Left" VerticalScrollBarVisibility="Auto" Width="240">
|
<ScrollViewer DockPanel.Dock="Left" VerticalScrollBarVisibility="Auto" Width="300" Margin="10">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<ListBox Items="{CompiledBinding ScriptConfigurations}" SelectedItem="{CompiledBinding SelectedScript}">
|
<ListBox Items="{CompiledBinding ScriptConfigurations}" SelectedItem="{CompiledBinding SelectedScript}">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
@ -29,7 +31,8 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{CompiledBinding ScriptConfiguration.Name}"
|
Text="{CompiledBinding ScriptConfiguration.Name}"
|
||||||
IsVisible="{CompiledBinding !ScriptConfiguration.HasChanges}" />
|
IsVisible="{CompiledBinding !ScriptConfiguration.HasChanges}"
|
||||||
|
TextTrimming="CharacterEllipsis" />
|
||||||
<StackPanel Grid.Row="0"
|
<StackPanel Grid.Row="0"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@ -78,7 +81,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
<Border DockPanel.Dock="Top" Classes="router-container">
|
<Border DockPanel.Dock="Top" Classes="router-container" Margin="0 10 0 0">
|
||||||
<ContentControl Content="{CompiledBinding ScriptEditorViewModel}" />
|
<ContentControl Content="{CompiledBinding ScriptEditorViewModel}" />
|
||||||
</Border>
|
</Border>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Avalonia;
|
using System.ComponentModel;
|
||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
@ -6,12 +7,28 @@ namespace Artemis.UI.Screens.Scripting;
|
|||||||
|
|
||||||
public partial class ScriptsDialogView : ReactiveCoreWindow<ScriptsDialogViewModel>
|
public partial class ScriptsDialogView : ReactiveCoreWindow<ScriptsDialogViewModel>
|
||||||
{
|
{
|
||||||
|
private bool _canClose;
|
||||||
|
|
||||||
public ScriptsDialogView()
|
public ScriptsDialogView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
this.AttachDevTools();
|
this.AttachDevTools();
|
||||||
#endif
|
#endif
|
||||||
|
Closing += OnClosing;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnClosing(object? sender, CancelEventArgs e)
|
||||||
|
{
|
||||||
|
if (_canClose)
|
||||||
|
return;
|
||||||
|
|
||||||
|
e.Cancel = true;
|
||||||
|
if (ViewModel == null || await ViewModel.CanClose())
|
||||||
|
{
|
||||||
|
_canClose = true;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
|
|||||||
@ -143,4 +143,18 @@ public class ScriptsDialogViewModel : DialogViewModelBase<object?>
|
|||||||
// Select the new script
|
// Select the new script
|
||||||
SelectedScript = ScriptConfigurations.LastOrDefault();
|
SelectedScript = ScriptConfigurations.LastOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> CanClose()
|
||||||
|
{
|
||||||
|
if (!ScriptConfigurations.Any(s => s.ScriptConfiguration.HasChanges))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool result = await _windowService.ShowConfirmContentDialog("Discard changes", "One or more scripts still have pending changes, do you want to discard them?");
|
||||||
|
if (!result)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (ScriptConfigurationViewModel scriptConfigurationViewModel in ScriptConfigurations)
|
||||||
|
scriptConfigurationViewModel.ScriptConfiguration.DiscardPendingChanges();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -23,11 +23,7 @@ public class ViewLocator : IDataTemplate
|
|||||||
throw new ArtemisUIException($"The views of activatable view models should inherit ReactiveUserControl<T>, in this case ReactiveUserControl<{data.GetType().Name}>.");
|
throw new ArtemisUIException($"The views of activatable view models should inherit ReactiveUserControl<T>, in this case ReactiveUserControl<{data.GetType().Name}>.");
|
||||||
|
|
||||||
if (type != null)
|
if (type != null)
|
||||||
{
|
|
||||||
Debug.WriteLine("[ViewLocator] Creating instance of '{0}'", type);
|
|
||||||
return (Control) Activator.CreateInstance(type)!;
|
return (Control) Activator.CreateInstance(type)!;
|
||||||
}
|
|
||||||
|
|
||||||
return new TextBlock {Text = "Not Found: " + name};
|
return new TextBlock {Text = "Not Found: " + name};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user