using Artemis.UI.Shared.Services.ProfileEditor.Commands;
using Artemis.UI.Shared.Tests.Infrastructure;
using RGB.NET.Core;
namespace Artemis.UI.Shared.Tests.ProfileEditor;
///
/// Moving through time in the editor, which overrides the timelines of the profile being edited, and suspending editing
///
public class ProfileEditorTimeTests : ProfileEditorTestBase
{
[Fact]
public async Task ChangeTime_MovesTheTimelineOfEveryElement()
{
Folder folder = Harness.AddFolder(Root, "Folder");
Layer layer = AddLayer("Layer", folder, LedId.Keyboard_A);
await StartEditing();
Service.ChangeTime(TimeSpan.FromSeconds(1.5));
Current(Service.Time).ShouldBe(TimeSpan.FromSeconds(1.5));
foreach (RenderProfileElement element in new RenderProfileElement[] {Root, folder, layer})
{
element.Timeline.Position.ShouldBe(TimeSpan.FromSeconds(1.5));
element.Timeline.IsOverridden.ShouldBeTrue();
}
}
[Fact]
public async Task ChangeTime_EnablesElements()
{
Folder folder = Harness.AddFolder(Root, "Folder");
Layer layer = AddLayer("Layer", folder, LedId.Keyboard_A);
folder.Disable();
layer.Disable();
await StartEditing();
Service.ChangeTime(TimeSpan.FromSeconds(1));
folder.Enabled.ShouldBeTrue();
layer.Enabled.ShouldBeTrue();
}
[Fact]
public async Task ChangeTime_AppliesKeyframesAtTheNewTime()
{
Layer layer = AddLayer("Layer", null, LedId.Keyboard_A);
FloatLayerProperty opacity = layer.Transform.Opacity;
opacity.KeyframesEnabled = true;
opacity.AddKeyframe(new LayerPropertyKeyframe(0, TimeSpan.Zero, Easings.Functions.Linear, opacity));
opacity.AddKeyframe(new LayerPropertyKeyframe(100, TimeSpan.FromSeconds(2), Easings.Functions.Linear, opacity));
await StartEditing();
Service.ChangeTime(TimeSpan.FromSeconds(1));
opacity.CurrentValue.ShouldBe(50, 0.01f);
Service.ChangeTime(TimeSpan.FromSeconds(2));
opacity.CurrentValue.ShouldBe(100, 0.01f);
}
[Fact]
public async Task ChangeTime_DisablesSuspendedElementsAndSkipsTheirChildren()
{
Folder folder = Harness.AddFolder(Root, "Folder");
Layer layer = AddLayer("Layer", folder, LedId.Keyboard_A);
await StartEditing();
Service.ChangeTime(TimeSpan.FromSeconds(1));
folder.Suspended = true;
Service.ChangeTime(TimeSpan.FromSeconds(2));
// Disabling a folder disables its children, their timelines are left where they were
folder.Enabled.ShouldBeFalse();
layer.Enabled.ShouldBeFalse();
layer.Timeline.Position.ShouldBe(TimeSpan.FromSeconds(1));
}
[Fact]
public void ChangeTime_WithoutProfile_OnlyChangesTheTime()
{
Layer layer = AddLayer("Layer", null, LedId.Keyboard_A);
Service.ChangeTime(TimeSpan.FromSeconds(1));
Current(Service.Time).ShouldBe(TimeSpan.FromSeconds(1));
layer.Timeline.IsOverridden.ShouldBeFalse();
}
[Fact]
public async Task ChangeTime_WhileEditingIsSuspended_LeavesTheProfileAlone()
{
Layer layer = AddLayer("Layer", null, LedId.Keyboard_A);
await StartEditing();
Service.ChangeSuspendedEditing(true);
Service.ChangeTime(TimeSpan.FromSeconds(1));
Current(Service.Time).ShouldBe(TimeSpan.FromSeconds(1));
layer.Timeline.Position.ShouldNotBe(TimeSpan.FromSeconds(1));
}
[Fact]
public async Task ExecuteCommand_AppliesTheCurrentTimeToTheChangedProfile()
{
await StartEditing();
Service.ChangeTime(TimeSpan.FromSeconds(1));
Layer layer = new(Root, "New layer");
Service.ExecuteCommand(new AddProfileElement(layer, Root, 0));
layer.Timeline.Position.ShouldBe(TimeSpan.FromSeconds(1));
}
[Fact]
public async Task SuspendingEditing_StopsPlayingAndHandsTheProfileBackToNormalPlayback()
{
Layer layer = AddLayer("Layer", null, LedId.Keyboard_A);
await StartEditing();
Service.ChangeTime(TimeSpan.FromSeconds(2));
Service.Play();
Service.ChangeSuspendedEditing(true);
Current(Service.SuspendedEditing).ShouldBeTrue();
Current(Service.Playing).ShouldBeFalse();
ProfileService.UpdateFocusProfile.ShouldBeTrue();
// The profile is reset so it plays from the start
layer.Timeline.Position.ShouldBe(TimeSpan.Zero);
// The editor keeps its own time
Current(Service.Time).ShouldBe(TimeSpan.FromSeconds(2));
}
[Fact]
public async Task ResumingEditing_TakesBackControlAndAppliesTheTime()
{
Layer layer = AddLayer("Layer", null, LedId.Keyboard_A);
await StartEditing();
Service.ChangeTime(TimeSpan.FromSeconds(2));
Service.ChangeSuspendedEditing(true);
Service.ChangeSuspendedEditing(false);
Current(Service.SuspendedEditing).ShouldBeFalse();
ProfileService.UpdateFocusProfile.ShouldBeFalse();
Current(Service.Time).ShouldBe(TimeSpan.FromSeconds(2));
layer.Timeline.Position.ShouldBe(TimeSpan.FromSeconds(2));
}
[Fact]
public void ResumingEditing_WithoutProfile_LeavesTheProfileServiceAlone()
{
Service.ChangeSuspendedEditing(true);
ProfileService.UpdateFocusProfile.ShouldBeTrue();
Service.ChangeSuspendedEditing(false);
ProfileService.UpdateFocusProfile.ShouldBeTrue();
}
[Fact]
public async Task ChangeSuspendedEditing_ToTheCurrentValue_DoesNothing()
{
await StartEditing();
List received = [];
using IDisposable _ = Service.SuspendedEditing.Subscribe(received.Add);
Service.ChangeSuspendedEditing(false);
received.ShouldBe([false]);
ProfileService.UpdateFocusProfile.ShouldBeFalse();
}
}