Workshop - Layout info WIP

This commit is contained in:
Robert committed 2023-10-23 19:33:38 +02:00
1 parent c77d51fb58
commit f4b9b67f1a
25 files changed
+361 -63

No files matched your search

@@ -0,0 +1,6 @@
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
public interface IEntrySource
{
}
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using Artemis.Core;
using Artemis.WebClient.Workshop;
using KeyboardLayoutType = Artemis.WebClient.Workshop.KeyboardLayoutType;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
public class LayoutEntrySource : IEntrySource
{
public LayoutEntrySource(ArtemisLayout layout)
{
Layout = layout;
}
public ArtemisLayout Layout { get; set; }
public List<LayoutInfo> LayoutInfo { get; } = new();
}
public class LayoutInfo
{
public Guid DeviceProvider { get; set; }
public RGBDeviceType DeviceType { get; set; }
public string Model { get; set; }
public string Vendor { get; set; }
public string? LogicalLayout { get; set; }
public KeyboardLayoutType? PhysicalLayout { get; set; }
}
@@ -0,0 +1,13 @@
using Artemis.Core;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
public class ProfileEntrySource : IEntrySource
{
public ProfileEntrySource(ProfileConfiguration profileConfiguration)
{
ProfileConfiguration = profileConfiguration;
}
public ProfileConfiguration ProfileConfiguration { get; set; }
}
@@ -7,7 +7,7 @@ using Artemis.UI.Shared.Services;
using Artemis.WebClient.Workshop;
using DryIoc;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
public class SubmissionWizardState
{
@@ -34,7 +34,7 @@ public class SubmissionWizardState
public List<string> Tags { get; set; } = new();
public List<Stream> Images { get; set; } = new();
public object? EntrySource { get; set; }
public IEntrySource? EntrySource { get; set; }
public void ChangeScreen<TSubmissionViewModel>() where TSubmissionViewModel : SubmissionViewModel
{
@@ -1,4 +1,5 @@
using Artemis.UI.Screens.Workshop.CurrentUser;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Artemis.WebClient.Workshop;
@@ -0,0 +1,43 @@
<UserControl xmlns="https://github.com/avaloniaui"
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:layout="clr-namespace:Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Layout"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Layout.LayoutInfoStepView"
x:DataType="layout:LayoutInfoStepViewModel">
<Grid RowDefinitions="Auto,*">
<StackPanel>
<StackPanel.Styles>
<Styles>
<Style Selector="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"></Setter>
</Style>
</Styles>
</StackPanel.Styles>
<TextBlock Theme="{StaticResource TitleTextBlockStyle}" TextWrapping="Wrap">
Layout information
</TextBlock>
<TextBlock TextWrapping="Wrap">
The information below is used by Artemis to automatically find your layout.
Some layouts can be shared across different devices and here you have a chance to set that up.
</TextBlock>
</StackPanel>
<ScrollViewer Grid.Row="1"
Grid.Column="0"
Margin="0 10 0 0"
Classes="with-padding"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
VerticalAlignment="Top">
<ItemsRepeater ItemsSource="{CompiledBinding LayoutInfo}">
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<ContentControl Content="{CompiledBinding}" />
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollViewer>
</Grid>
</UserControl>
@@ -0,0 +1,14 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Layout;
public partial class LayoutInfoStepView : ReactiveUserControl<LayoutInfoStepViewModel>
{
public LayoutInfoStepView()
{
InitializeComponent();
}
}
@@ -0,0 +1,25 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Disposables;
using Artemis.UI.Screens.Workshop.Layout;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
using DynamicData;
using ReactiveUI;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Layout;
public class LayoutInfoStepViewModel : SubmissionViewModel
{
public LayoutInfoStepViewModel()
{
GoBack = ReactiveCommand.Create(() => State.ChangeScreen<LayoutSelectionStepViewModel>());
this.WhenActivated((CompositeDisposable _) =>
{
LayoutInfo.Clear();
if (State.EntrySource is LayoutEntrySource layoutEntrySource)
LayoutInfo.AddRange(layoutEntrySource.LayoutInfo.Select(i => new LayoutInfoViewModel(layoutEntrySource.Layout, i)));
});
}
public ObservableCollection<LayoutInfoViewModel> LayoutInfo { get; } = new();
}
@@ -4,22 +4,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
xmlns:layout="clr-namespace:Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Layout"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Layout.LayoutSelectionStepView"
x:DataType="layout:LayoutSelectionStepViewModel">
<UserControl.Resources>
<VisualBrush x:Key="LargeCheckerboardBrush" TileMode="Tile" Stretch="Uniform" SourceRect="0,0,20,20">
<VisualBrush.Visual>
<Canvas Width="20" Height="20">
<Rectangle Width="10" Height="10" Fill="Black" Opacity="0.15" />
<Rectangle Width="10" Height="10" Canvas.Left="10" />
<Rectangle Width="10" Height="10" Canvas.Top="10" />
<Rectangle Width="10" Height="10" Canvas.Left="10" Canvas.Top="10" Fill="Black" Opacity="0.15" />
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</UserControl.Resources>
<Grid RowDefinitions="Auto,*">
<StackPanel>
<StackPanel.Styles>
@@ -5,16 +5,15 @@ using Artemis.Core.Services;
using PropertyChanged.SourceGenerator;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Artemis.UI.Extensions;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
using Artemis.UI.Shared.Extensions;
using Artemis.UI.Shared.Services;
using Avalonia;
using Avalonia.Media.Imaging;
using Material.Icons;
using RGB.NET.Core;
using SkiaSharp;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Layout;
@@ -36,10 +35,20 @@ public partial class LayoutSelectionStepViewModel : SubmissionViewModel
.OrderBy(d => d.RgbDevice.DeviceInfo.Model)
);
GoBack = ReactiveCommand.Create(() => State.ChangeScreen<EntryTypeStepViewModel>());
Continue = ReactiveCommand.Create(ExecuteContinue, this.WhenAnyValue(vm => vm.Layout).Select(p => p != null));
this.WhenAnyValue(vm => vm.SelectedDevice).WhereNotNull().Subscribe(d => Layout = d.Layout);
this.WhenAnyValue(vm => vm.Layout).Subscribe(CreatePreviewDevice);
this.WhenActivated((CompositeDisposable _) =>
{
ShowGoBack = State.EntryId == null;
if (State.EntrySource is not LayoutEntrySource layoutEntrySource)
return;
Layout = layoutEntrySource.Layout;
SelectedDevice = Devices.FirstOrDefault(d => d.Layout == Layout);
});
}
public ObservableCollection<ArtemisDevice> Devices { get; }
@@ -78,12 +87,22 @@ public partial class LayoutSelectionStepViewModel : SubmissionViewModel
if (Layout == null)
return;
State.EntrySource = Layout;
State.EntrySource = new LayoutEntrySource(Layout);
State.Name = Layout.RgbLayout.Name ?? "";
State.Summary = !string.IsNullOrWhiteSpace(Layout.RgbLayout.Vendor)
? $"{Layout.RgbLayout.Vendor} {Layout.RgbLayout.Type} device layout"
: $"{Layout.RgbLayout.Type} device layout";
State.Categories = new List<long> {8}; // Device category, yes this could change but why would it
State.Icon?.Dispose();
State.Icon = GetDeviceIcon();
State.ChangeScreen<LayoutInfoStepViewModel>();
}
private Stream GetDeviceIcon()
{
// Go through the hassle of resizing the image to 128x128 without losing aspect ratio, padding is added for this
using RenderTargetBitmap image = Layout.RenderLayout(false);
using MemoryStream stream = new();
@@ -99,18 +118,14 @@ public partial class LayoutSelectionStepViewModel : SubmissionViewModel
SKSizeI scaledDimensions = new((int) Math.Floor(sourceWidth * scale), (int) Math.Floor(sourceHeight * scale));
SKPointI offset = new((128 - scaledDimensions.Width) / 2, (128 - scaledDimensions.Height) / 2);
using (SKBitmap? scaleBitmap = sourceBitmap.Resize(scaledDimensions, SKFilterQuality.High))
using (SKBitmap targetBitmap = new(128, 128))
using (SKCanvas canvas = new(targetBitmap))
{
canvas.Clear(SKColors.Transparent);
canvas.DrawBitmap(scaleBitmap, offset.X, offset.Y);
targetBitmap.Encode(output, SKEncodedImageFormat.Png, 100);
output.Seek(0, SeekOrigin.Begin);
}
using SKBitmap? scaleBitmap = sourceBitmap.Resize(scaledDimensions, SKFilterQuality.High);
using SKBitmap targetBitmap = new(128, 128);
using SKCanvas canvas = new(targetBitmap);
canvas.Clear(SKColors.Transparent);
canvas.DrawBitmap(scaleBitmap, offset.X, offset.Y);
targetBitmap.Encode(output, SKEncodedImageFormat.Png, 100);
output.Seek(0, SeekOrigin.Begin);
State.Icon?.Dispose();
State.Icon = output;
State.ChangeScreen<SpecificationsStepViewModel>();
return output;
}
}
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
using Artemis.UI.Shared.Services;
using DynamicData;
using DynamicData.Aggregation;
@@ -34,12 +35,14 @@ public class ProfileAdaptionHintsStepViewModel : SubmissionViewModel
this.WhenActivated((CompositeDisposable _) =>
{
if (State.EntrySource is ProfileConfiguration profileConfiguration && profileConfiguration.Profile != null)
_layers.Edit(l =>
{
l.Clear();
l.AddRange(profileConfiguration.Profile.GetAllLayers().Select(getLayerViewModel));
});
if (State.EntrySource is not ProfileEntrySource profileEntrySource || profileEntrySource.ProfileConfiguration.Profile == null)
return;
_layers.Edit(l =>
{
l.Clear();
l.AddRange(profileEntrySource.ProfileConfiguration.Profile.GetAllLayers().Select(getLayerViewModel));
});
});
}
@@ -7,6 +7,7 @@ using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Extensions;
using Artemis.UI.Screens.Workshop.Profile;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
using Material.Icons;
using PropertyChanged.SourceGenerator;
using ReactiveUI;
@@ -38,8 +39,8 @@ public partial class ProfileSelectionStepViewModel : SubmissionViewModel
this.WhenActivated((CompositeDisposable _) =>
{
ShowGoBack = State.EntryId == null;
if (State.EntrySource is ProfileConfiguration profileConfiguration)
SelectedProfile = Profiles.FirstOrDefault(p => p.ProfileId == profileConfiguration.ProfileId);
if (State.EntrySource is ProfileEntrySource profileEntrySource)
SelectedProfile = Profiles.FirstOrDefault(p => p.ProfileId == profileEntrySource.ProfileConfiguration.ProfileId);
});
}
@@ -66,7 +67,7 @@ public partial class ProfileSelectionStepViewModel : SubmissionViewModel
if (SelectedProfile == null)
return;
State.EntrySource = SelectedProfile;
State.EntrySource = new ProfileEntrySource(SelectedProfile);
State.Name = SelectedProfile.Name;
State.Icon = SelectedProfile.Icon.GetIconStream();
@@ -39,7 +39,7 @@ public partial class SpecificationsStepViewModel : SubmissionViewModel
switch (State.EntryType)
{
case EntryType.Layout:
State.ChangeScreen<LayoutSelectionStepViewModel>();
State.ChangeScreen<LayoutInfoStepViewModel>();
break;
case EntryType.Plugin:
break;
@@ -1,4 +1,5 @@
using System.Reactive;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
using Artemis.UI.Shared;
using PropertyChanged.SourceGenerator;
using ReactiveUI;
@@ -1,4 +1,5 @@
using Artemis.UI.Screens.Workshop.CurrentUser;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;