Skip to content

Commit

Permalink
WIP DataSet composition editing
Browse files Browse the repository at this point in the history
  • Loading branch information
Neakita committed Sep 18, 2024
1 parent 334d79d commit 4bcdf7b
Show file tree
Hide file tree
Showing 15 changed files with 246 additions and 37 deletions.
1 change: 1 addition & 0 deletions SightKeeper.Avalonia/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<StyleInclude Source="avares://Sightful.Avalonia/DefaultTheme.axaml"/>
<StyleInclude Source="avares://Sightful.Avalonia.TreeDataGrid/SightfulTreeDataGridTheme.axaml"/>
<StyleInclude Source="avares://Sightful.Avalonia.Controls.PropertyGrid/PropertyHeader.axaml"/>
<StyleInclude Source="avares://Sightful.Avalonia.Controls/MultiSlider.axaml"/>
</Application.Styles>

</Application>
34 changes: 34 additions & 0 deletions SightKeeper.Avalonia/DataSets/Compositions/CompositionViewModel.cs
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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<decimal> _opacities;
}
Original file line number Diff line number Diff line change
@@ -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;
}
14 changes: 12 additions & 2 deletions SightKeeper.Avalonia/DataSets/Dialogs/DataSetEditorViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,6 +22,13 @@ public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged
}

public IReadOnlyCollection<Game> Games { get; }

public IReadOnlyCollection<CompositionViewModel> Compositions { get; } =
[
new FixedTransparentCompositionViewModel(),
new FloatingTransparentCompositionViewModel()
];

public bool HasErrors => _validator.HasErrors;

public DataSetEditorViewModel(GamesDataAccess gamesDataAccess, IValidator<DataSetData> validator)
Expand All @@ -35,7 +43,7 @@ public DataSetEditorViewModel(GamesDataAccess gamesDataAccess, IValidator<DataSe
_name = dataSet.Name;
_description = dataSet.Description;
_game = dataSet.Game;
_composition = dataSet.Composition;
_composition = CompositionViewModel.Create(dataSet.Composition);
_validator = new ViewModelValidator<DataSetData>(validator, this, this);
}

Expand All @@ -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();
}
49 changes: 49 additions & 0 deletions SightKeeper.Avalonia/DataSets/Dialogs/GeneralDataSetEditor.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand All @@ -17,5 +19,52 @@
<ComboBox SelectedItem="{Binding Game}"
ItemsSource="{Binding Games}"/>
</HeaderedContentControl>
<HeaderedContentControl Header="Composition">
<StackPanel Classes="regular-spacing">
<ComboBox SelectedItem="{Binding Composition}"
ItemsSource="{Binding Compositions}"
DisplayMemberBinding="{Binding DisplayName}"/>
<Slider
Value="{Binding Composition.MaximumScreenshotsDelayInMilliseconds}"
Minimum="10"
Maximum="200"
TickFrequency="10"
IsVisible="{Binding Composition, Converter={x:Static ObjectConverters.IsNotNull}}"/>
<ContentControl Content="{Binding Composition}">
<ContentControl.DataTemplates>
<DataTemplate DataType="compositions:FixedTransparentCompositionViewModel">
<StackPanel Classes="regular-spacing">
<Slider
Value="{Binding ScreenshotsCount}"
Minimum="2"
Maximum="8"
TickFrequency="1"
IsSnapToTickEnabled="True"/>
<controls:MultiSlider
Values="{Binding Opacities}"
Increment="0.05"
MinimumValue="0.05"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="compositions:FloatingTransparentCompositionViewModel">
<StackPanel Classes="regular-spacing">
<Slider
Value="{Binding SeriesDurationInMilliseconds}"
Minimum="100"
Maximum="1000"
TickFrequency="50"
IsSnapToTickEnabled="True"/>
<Slider
Value="{Binding MinimumOpacity}"
Minimum="0"
Maximum="90"
TickFrequency="5"
IsSnapToTickEnabled="True"/>
</StackPanel>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</StackPanel>
</HeaderedContentControl>
</StackPanel>
</UserControl>
1 change: 1 addition & 0 deletions SightKeeper.Avalonia/SightKeeper.Avalonia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

<ItemGroup>
<ProjectReference Include="..\..\Sightful.Theme\Sightful.Avalonia.Controls.PropertyGrid\Sightful.Avalonia.Controls.PropertyGrid.csproj" OutputItemType="Analyzer" />
<ProjectReference Include="..\..\Sightful.Theme\Sightful.Avalonia.Controls\Sightful.Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\Sightful.Theme\Sightful.Avalonia\Sightful.Avalonia.csproj" />
<ProjectReference Include="..\..\Sightful.Theme\Sightful.Avalonia.TreeDataGrid\Sightful.Avalonia.TreeDataGrid.csproj" />
<ProjectReference Include="..\SightKeeper.Data\SightKeeper.Data.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace SightKeeper.Data.Binary.Model.DataSets.Compositions;

/// <summary>
/// MemoryPackable version of <see cref="TransparentComposition"/>
/// MemoryPackable version of <see cref="FixedTransparentComposition"/>
/// </summary>
[MemoryPackable]
internal sealed partial class PackableTransparentComposition : PackableComposition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Exception>(() => new FixedTransparentComposition(TimeSpan.FromMilliseconds(-1), [0.5f, 0.5f]));
}

[Fact]
public void ShouldNotCreateWithOnlyOneOpacity()
{
Assert.ThrowsAny<Exception>(() => new FixedTransparentComposition(TimeSpan.FromMilliseconds(50), [1]));
}

[Fact]
public void ShouldNotCreateWithOpacitiesSumNotEqualToOne()
{
Assert.ThrowsAny<Exception>(() => new FixedTransparentComposition(TimeSpan.FromMilliseconds(50), [0.1f, 0.3f, 0.5f]));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace SightKeeper.Domain.Model.DataSets.Screenshots;

public sealed class TransparentComposition : Composition
public sealed class FixedTransparentComposition : Composition
{
public ImmutableArray<float> Opacities
{
Expand All @@ -15,7 +15,7 @@ public ImmutableArray<float> Opacities
}
}

public TransparentComposition(
public FixedTransparentComposition(
TimeSpan maximumScreenshotsDelay,
ImmutableArray<float> opacities)
: base(maximumScreenshotsDelay)
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit 4bcdf7b

Please sign in to comment.