diff --git a/SightKeeper.Avalonia/App.axaml b/SightKeeper.Avalonia/App.axaml
index 5ec3813b..30f79fbe 100644
--- a/SightKeeper.Avalonia/App.axaml
+++ b/SightKeeper.Avalonia/App.axaml
@@ -7,6 +7,7 @@
+
\ No newline at end of file
diff --git a/SightKeeper.Avalonia/DataSets/Compositions/CompositionViewModel.cs b/SightKeeper.Avalonia/DataSets/Compositions/CompositionViewModel.cs
new file mode 100644
index 00000000..b74fce34
--- /dev/null
+++ b/SightKeeper.Avalonia/DataSets/Compositions/CompositionViewModel.cs
@@ -0,0 +1,34 @@
+using System;
+using CommunityToolkit.Mvvm.ComponentModel;
+using SightKeeper.Domain.Model.DataSets.Screenshots;
+
+namespace SightKeeper.Avalonia.DataSets.Compositions;
+
+internal abstract partial class CompositionViewModel : ViewModel
+{
+ public abstract string DisplayName { get; }
+
+ public static CompositionViewModel? Create(Composition? composition) => composition switch
+ {
+ null => null,
+ FixedTransparentComposition fixedTransparent => new FixedTransparentCompositionViewModel(fixedTransparent),
+ FloatingTransparentComposition floatingTransparent => new FloatingTransparentCompositionViewModel(floatingTransparent),
+ _ => throw new ArgumentOutOfRangeException(nameof(composition))
+ };
+
+ public TimeSpan MaximumScreenshotsDelay => TimeSpan.FromMilliseconds(MaximumScreenshotsDelayInMilliseconds);
+
+ public abstract Composition ToComposition();
+
+ protected CompositionViewModel()
+ {
+ _maximumScreenshotsDelayInMilliseconds = 50;
+ }
+
+ protected CompositionViewModel(Composition composition)
+ {
+ _maximumScreenshotsDelayInMilliseconds = (ushort)composition.MaximumScreenshotsDelay.TotalMilliseconds;
+ }
+
+ [ObservableProperty] private ushort _maximumScreenshotsDelayInMilliseconds;
+}
\ No newline at end of file
diff --git a/SightKeeper.Avalonia/DataSets/Compositions/FixedTransparentCompositionViewModel.cs b/SightKeeper.Avalonia/DataSets/Compositions/FixedTransparentCompositionViewModel.cs
new file mode 100644
index 00000000..2b91370d
--- /dev/null
+++ b/SightKeeper.Avalonia/DataSets/Compositions/FixedTransparentCompositionViewModel.cs
@@ -0,0 +1,42 @@
+using System.Collections.Immutable;
+using System.Linq;
+using CommunityToolkit.Mvvm.ComponentModel;
+using SightKeeper.Domain.Model.DataSets.Screenshots;
+
+namespace SightKeeper.Avalonia.DataSets.Compositions;
+
+internal sealed partial class FixedTransparentCompositionViewModel : CompositionViewModel
+{
+ public override string DisplayName => "Fixed transparent";
+
+ public byte ScreenshotsCount
+ {
+ get => (byte)Opacities.Count;
+ set
+ {
+ var delta = value - Opacities.Count;
+ OnPropertyChanging();
+ if (delta > 0)
+ Opacities = Opacities.AddRange(Enumerable.Repeat(0.1m, delta));
+ else if (delta < 0)
+ Opacities = Opacities.RemoveRange(Opacities.Count + delta, -delta);
+ OnPropertyChanged();
+ }
+ }
+
+ public FixedTransparentCompositionViewModel()
+ {
+ _opacities = [0.1m, 0.2m, 0.7m];
+ }
+
+ public FixedTransparentCompositionViewModel(FixedTransparentComposition composition) : base(composition)
+ {
+ _opacities = composition.Opacities.Select(opacity => (decimal)opacity).ToImmutableList();
+ }
+
+ public override FixedTransparentComposition ToComposition() =>
+ new(MaximumScreenshotsDelay,
+ Opacities.Select(opacity => (float)opacity).ToImmutableArray());
+
+ [ObservableProperty] private ImmutableList _opacities;
+}
\ No newline at end of file
diff --git a/SightKeeper.Avalonia/DataSets/Compositions/FloatingTransparentCompositionViewModel.cs b/SightKeeper.Avalonia/DataSets/Compositions/FloatingTransparentCompositionViewModel.cs
new file mode 100644
index 00000000..645932c0
--- /dev/null
+++ b/SightKeeper.Avalonia/DataSets/Compositions/FloatingTransparentCompositionViewModel.cs
@@ -0,0 +1,30 @@
+using System;
+using CommunityToolkit.Mvvm.ComponentModel;
+using SightKeeper.Domain.Model.DataSets.Screenshots;
+
+namespace SightKeeper.Avalonia.DataSets.Compositions;
+
+internal sealed partial class FloatingTransparentCompositionViewModel : CompositionViewModel
+{
+ public override string DisplayName => "Floating transparent";
+
+ public TimeSpan SeriesDuration => TimeSpan.FromMilliseconds(SeriesDurationInMilliseconds);
+
+ public FloatingTransparentCompositionViewModel()
+ {
+ _seriesDurationInMilliseconds = 500;
+ }
+
+ public FloatingTransparentCompositionViewModel(FloatingTransparentComposition composition) : base(composition)
+ {
+ _seriesDurationInMilliseconds = (ushort)composition.SeriesDuration.TotalMilliseconds;
+ }
+
+ public override FloatingTransparentComposition ToComposition()
+ {
+ return new FloatingTransparentComposition(MaximumScreenshotsDelay, SeriesDuration, MinimumOpacity);
+ }
+
+ [ObservableProperty] private ushort _seriesDurationInMilliseconds;
+ [ObservableProperty] private float _minimumOpacity;
+}
\ No newline at end of file
diff --git a/SightKeeper.Avalonia/DataSets/Dialogs/DataSetEditorViewModel.cs b/SightKeeper.Avalonia/DataSets/Dialogs/DataSetEditorViewModel.cs
index ad4cccb1..98fd9f33 100644
--- a/SightKeeper.Avalonia/DataSets/Dialogs/DataSetEditorViewModel.cs
+++ b/SightKeeper.Avalonia/DataSets/Dialogs/DataSetEditorViewModel.cs
@@ -6,6 +6,7 @@
using FluentValidation;
using SightKeeper.Application.DataSets;
using SightKeeper.Application.Games;
+using SightKeeper.Avalonia.DataSets.Compositions;
using SightKeeper.Domain.Model;
using SightKeeper.Domain.Model.DataSets;
using SightKeeper.Domain.Model.DataSets.Screenshots;
@@ -21,6 +22,13 @@ public event EventHandler? ErrorsChanged
}
public IReadOnlyCollection Games { get; }
+
+ public IReadOnlyCollection Compositions { get; } =
+ [
+ new FixedTransparentCompositionViewModel(),
+ new FloatingTransparentCompositionViewModel()
+ ];
+
public bool HasErrors => _validator.HasErrors;
public DataSetEditorViewModel(GamesDataAccess gamesDataAccess, IValidator validator)
@@ -35,7 +43,7 @@ public DataSetEditorViewModel(GamesDataAccess gamesDataAccess, IValidator(validator, this, this);
}
@@ -54,5 +62,7 @@ public void Dispose()
[ObservableProperty] private string _name = string.Empty;
[ObservableProperty] private string _description = string.Empty;
[ObservableProperty] private Game? _game;
- [ObservableProperty] private Composition? _composition;
+ [ObservableProperty] private CompositionViewModel? _composition;
+
+ Composition? DataSetData.Composition => Composition?.ToComposition();
}
\ No newline at end of file
diff --git a/SightKeeper.Avalonia/DataSets/Dialogs/GeneralDataSetEditor.axaml b/SightKeeper.Avalonia/DataSets/Dialogs/GeneralDataSetEditor.axaml
index 02f04fd3..9b28394b 100644
--- a/SightKeeper.Avalonia/DataSets/Dialogs/GeneralDataSetEditor.axaml
+++ b/SightKeeper.Avalonia/DataSets/Dialogs/GeneralDataSetEditor.axaml
@@ -3,6 +3,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SightKeeper.Avalonia.DataSets.Dialogs"
+ xmlns:compositions="clr-namespace:SightKeeper.Avalonia.DataSets.Compositions"
+ xmlns:controls="clr-namespace:Sightful.Avalonia.Controls;assembly=Sightful.Avalonia.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SightKeeper.Avalonia.DataSets.Dialogs.GeneralDataSetEditor"
x:DataType="local:DataSetEditorViewModel">
@@ -17,5 +19,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SightKeeper.Avalonia/SightKeeper.Avalonia.csproj b/SightKeeper.Avalonia/SightKeeper.Avalonia.csproj
index 9d996028..c49b1767 100644
--- a/SightKeeper.Avalonia/SightKeeper.Avalonia.csproj
+++ b/SightKeeper.Avalonia/SightKeeper.Avalonia.csproj
@@ -41,6 +41,7 @@
+
diff --git a/SightKeeper.Data/Binary/Conversion/DataSets/DataSetConverter.cs b/SightKeeper.Data/Binary/Conversion/DataSets/DataSetConverter.cs
index 38e9f9dc..06363a41 100644
--- a/SightKeeper.Data/Binary/Conversion/DataSets/DataSetConverter.cs
+++ b/SightKeeper.Data/Binary/Conversion/DataSets/DataSetConverter.cs
@@ -53,7 +53,7 @@ protected static PackableTag ConvertPlainTag(byte id, Tag tag)
return composition switch
{
null => null,
- TransparentComposition transparentComposition => new PackableTransparentComposition(
+ FixedTransparentComposition transparentComposition => new PackableTransparentComposition(
transparentComposition.MaximumScreenshotsDelay,
transparentComposition.Opacities),
_ => throw new ArgumentOutOfRangeException()
diff --git a/SightKeeper.Data/Binary/Model/DataSets/Compositions/PackableTransparentComposition.cs b/SightKeeper.Data/Binary/Model/DataSets/Compositions/PackableTransparentComposition.cs
index a59f0748..9a161bf8 100644
--- a/SightKeeper.Data/Binary/Model/DataSets/Compositions/PackableTransparentComposition.cs
+++ b/SightKeeper.Data/Binary/Model/DataSets/Compositions/PackableTransparentComposition.cs
@@ -5,7 +5,7 @@
namespace SightKeeper.Data.Binary.Model.DataSets.Compositions;
///
-/// MemoryPackable version of
+/// MemoryPackable version of
///
[MemoryPackable]
internal sealed partial class PackableTransparentComposition : PackableComposition
diff --git a/SightKeeper.Data/Binary/Replication/DataSets/DataSetReplicator.cs b/SightKeeper.Data/Binary/Replication/DataSets/DataSetReplicator.cs
index aa72d9e8..c028f641 100644
--- a/SightKeeper.Data/Binary/Replication/DataSets/DataSetReplicator.cs
+++ b/SightKeeper.Data/Binary/Replication/DataSets/DataSetReplicator.cs
@@ -75,7 +75,7 @@ protected virtual Tag ReplicateTag(
{
null => null,
PackableTransparentComposition transparentComposition =>
- new TransparentComposition(
+ new FixedTransparentComposition(
transparentComposition.MaximumScreenshotsDelay,
transparentComposition.Opacities),
_ => throw new ArgumentOutOfRangeException(nameof(composition))
diff --git a/SightKeeper.Domain.Tests/DataSets/Screenshots/FixedTransparentCompositionTests.cs b/SightKeeper.Domain.Tests/DataSets/Screenshots/FixedTransparentCompositionTests.cs
new file mode 100644
index 00000000..09745c74
--- /dev/null
+++ b/SightKeeper.Domain.Tests/DataSets/Screenshots/FixedTransparentCompositionTests.cs
@@ -0,0 +1,30 @@
+using SightKeeper.Domain.Model.DataSets.Screenshots;
+
+namespace SightKeeper.Domain.Tests.DataSets.Screenshots;
+
+public sealed class FixedTransparentCompositionTests
+{
+ [Fact]
+ public void ShouldCreate()
+ {
+ FixedTransparentComposition _ = new(TimeSpan.FromMilliseconds(50), [0.2f, 0.3f, 0.5f]);
+ }
+
+ [Fact]
+ public void ShouldNotCreateWithNegativeDelay()
+ {
+ Assert.ThrowsAny(() => new FixedTransparentComposition(TimeSpan.FromMilliseconds(-1), [0.5f, 0.5f]));
+ }
+
+ [Fact]
+ public void ShouldNotCreateWithOnlyOneOpacity()
+ {
+ Assert.ThrowsAny(() => new FixedTransparentComposition(TimeSpan.FromMilliseconds(50), [1]));
+ }
+
+ [Fact]
+ public void ShouldNotCreateWithOpacitiesSumNotEqualToOne()
+ {
+ Assert.ThrowsAny(() => new FixedTransparentComposition(TimeSpan.FromMilliseconds(50), [0.1f, 0.3f, 0.5f]));
+ }
+}
\ No newline at end of file
diff --git a/SightKeeper.Domain.Tests/DataSets/Screenshots/TransparentCompositionTests.cs b/SightKeeper.Domain.Tests/DataSets/Screenshots/TransparentCompositionTests.cs
deleted file mode 100644
index 49b3526b..00000000
--- a/SightKeeper.Domain.Tests/DataSets/Screenshots/TransparentCompositionTests.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using SightKeeper.Domain.Model.DataSets.Screenshots;
-
-namespace SightKeeper.Domain.Tests.DataSets.Screenshots;
-
-public sealed class TransparentCompositionTests
-{
- [Fact]
- public void ShouldCreate()
- {
- TransparentComposition _ = new(TimeSpan.FromMilliseconds(50), [0.2f, 0.3f, 0.5f]);
- }
-
- [Fact]
- public void ShouldNotCreateWithNegativeDelay()
- {
- Assert.ThrowsAny(() => new TransparentComposition(TimeSpan.FromMilliseconds(-1), [0.5f, 0.5f]));
- }
-
- [Fact]
- public void ShouldNotCreateWithOnlyOneOpacity()
- {
- Assert.ThrowsAny(() => new TransparentComposition(TimeSpan.FromMilliseconds(50), [1]));
- }
-
- [Fact]
- public void ShouldNotCreateWithOpacitiesSumNotEqualToOne()
- {
- Assert.ThrowsAny(() => new TransparentComposition(TimeSpan.FromMilliseconds(50), [0.1f, 0.3f, 0.5f]));
- }
-}
\ No newline at end of file
diff --git a/SightKeeper.Domain/Model/DataSets/Screenshots/TransparentComposition.cs b/SightKeeper.Domain/Model/DataSets/Screenshots/FixedTransparentComposition.cs
similarity index 83%
rename from SightKeeper.Domain/Model/DataSets/Screenshots/TransparentComposition.cs
rename to SightKeeper.Domain/Model/DataSets/Screenshots/FixedTransparentComposition.cs
index 7511f9a6..437fce79 100644
--- a/SightKeeper.Domain/Model/DataSets/Screenshots/TransparentComposition.cs
+++ b/SightKeeper.Domain/Model/DataSets/Screenshots/FixedTransparentComposition.cs
@@ -3,7 +3,7 @@
namespace SightKeeper.Domain.Model.DataSets.Screenshots;
-public sealed class TransparentComposition : Composition
+public sealed class FixedTransparentComposition : Composition
{
public ImmutableArray Opacities
{
@@ -15,7 +15,7 @@ public ImmutableArray Opacities
}
}
- public TransparentComposition(
+ public FixedTransparentComposition(
TimeSpan maximumScreenshotsDelay,
ImmutableArray opacities)
: base(maximumScreenshotsDelay)
diff --git a/SightKeeper.Domain/Model/DataSets/Screenshots/FloatingTransparentComposition.cs b/SightKeeper.Domain/Model/DataSets/Screenshots/FloatingTransparentComposition.cs
new file mode 100644
index 00000000..c5ac891a
--- /dev/null
+++ b/SightKeeper.Domain/Model/DataSets/Screenshots/FloatingTransparentComposition.cs
@@ -0,0 +1,35 @@
+using CommunityToolkit.Diagnostics;
+
+namespace SightKeeper.Domain.Model.DataSets.Screenshots;
+
+public sealed class FloatingTransparentComposition : Composition
+{
+ public TimeSpan SeriesDuration
+ {
+ get => _seriesDuration;
+ set
+ {
+ Guard.IsGreaterThan(value, TimeSpan.Zero);
+ _seriesDuration = value;
+ }
+ }
+
+ public float MinimumOpacity
+ {
+ get => _minimumOpacity;
+ set
+ {
+ Guard.IsInRange(value, 0, 1);
+ _minimumOpacity = value;
+ }
+ }
+
+ public FloatingTransparentComposition(TimeSpan maximumScreenshotsDelay, TimeSpan seriesDuration, float minimumOpacity) : base(maximumScreenshotsDelay)
+ {
+ SeriesDuration = seriesDuration;
+ MinimumOpacity = minimumOpacity;
+ }
+
+ private TimeSpan _seriesDuration;
+ private float _minimumOpacity;
+}
\ No newline at end of file
diff --git a/SightKeeper.sln b/SightKeeper.sln
index d8168256..8820566d 100644
--- a/SightKeeper.sln
+++ b/SightKeeper.sln
@@ -24,6 +24,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sightful.Avalonia.Controls.
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sightful", "Sightful", "{61ECB802-CDBC-4D92-869F-C0F305B6705C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sightful.Avalonia.Controls", "..\Sightful.Theme\Sightful.Avalonia.Controls\Sightful.Avalonia.Controls.csproj", "{0DAC9FFF-10BF-4E15-83B0-F22F7132991F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -70,6 +72,10 @@ Global
{F7114FB2-C0FF-4FC1-B047-7F2AB9F21EAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7114FB2-C0FF-4FC1-B047-7F2AB9F21EAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7114FB2-C0FF-4FC1-B047-7F2AB9F21EAD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0DAC9FFF-10BF-4E15-83B0-F22F7132991F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0DAC9FFF-10BF-4E15-83B0-F22F7132991F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0DAC9FFF-10BF-4E15-83B0-F22F7132991F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0DAC9FFF-10BF-4E15-83B0-F22F7132991F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4D385463-EE5E-4257-84C8-75C0A0018879} = {EC16BB21-7A91-4224-BAB7-4C896D7B2920}
@@ -77,5 +83,6 @@ Global
{542EC90B-A2D0-4055-95C6-3FCD5A8CA08D} = {61ECB802-CDBC-4D92-869F-C0F305B6705C}
{F7114FB2-C0FF-4FC1-B047-7F2AB9F21EAD} = {61ECB802-CDBC-4D92-869F-C0F305B6705C}
{25B85324-71B2-4011-8C8D-FDFF38668A00} = {61ECB802-CDBC-4D92-869F-C0F305B6705C}
+ {0DAC9FFF-10BF-4E15-83B0-F22F7132991F} = {61ECB802-CDBC-4D92-869F-C0F305B6705C}
EndGlobalSection
EndGlobal