mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Redid some of the surface editor and started working on layout saving
This commit is contained in:
1 parent
f3650445d9
commit
a34786fb5d
48 files changed
+1012
-107
No files matched your search
@@ -11,7 +11,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.4.0" newVersion="1.2.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
|
||||
@@ -59,7 +59,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.4.0" newVersion="1.4.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
@@ -87,7 +87,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
@@ -99,7 +99,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.5.0" newVersion="4.1.5.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
|
||||
@@ -119,8 +119,8 @@
|
||||
<Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.1.12.351, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.12\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Stylet, Version=1.1.22.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Stylet.1.1.22\lib\net45\Stylet.dll</HintPath>
|
||||
<Reference Include="Stylet, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Stylet.1.2.0\lib\net45\Stylet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.Core.Services.Storage;
|
||||
using Artemis.UI.ViewModels.Controls.RgbDevice;
|
||||
using Artemis.UI.ViewModels.Interfaces;
|
||||
using RGB.NET.Core;
|
||||
@@ -16,21 +19,23 @@ namespace Artemis.UI.ViewModels.Screens
|
||||
public class SurfaceEditorViewModel : Screen, ISurfaceEditorViewModel
|
||||
{
|
||||
private readonly IRgbService _rgbService;
|
||||
private readonly ISurfaceService _surfaceService;
|
||||
|
||||
|
||||
public SurfaceEditorViewModel(IRgbService rgbService)
|
||||
public SurfaceEditorViewModel(IRgbService rgbService, ISurfaceService surfaceService)
|
||||
{
|
||||
Devices = new ObservableCollection<RgbDeviceViewModel>();
|
||||
SurfaceConfigurations = new ObservableCollection<SurfaceConfiguration>();
|
||||
SelectionRectangle = new RectangleGeometry();
|
||||
|
||||
_rgbService = rgbService;
|
||||
_surfaceService = surfaceService;
|
||||
_rgbService.DeviceLoaded += RgbServiceOnDeviceLoaded;
|
||||
_rgbService.Surface.Updated += SurfaceOnUpdated;
|
||||
|
||||
foreach (var surfaceDevice in _rgbService.Surface.Devices)
|
||||
{
|
||||
var device = new RgbDeviceViewModel(surfaceDevice) {Cursor = Cursors.Hand};
|
||||
// device.SetColorsEnabled(false);
|
||||
device.SetColorsEnabled(false);
|
||||
|
||||
Devices.Add(device);
|
||||
}
|
||||
@@ -39,6 +44,10 @@ namespace Artemis.UI.ViewModels.Screens
|
||||
public RectangleGeometry SelectionRectangle { get; set; }
|
||||
public ObservableCollection<RgbDeviceViewModel> Devices { get; set; }
|
||||
|
||||
public SurfaceConfiguration SelectedSurfaceConfiguration { get; set; }
|
||||
public ObservableCollection<SurfaceConfiguration> SurfaceConfigurations { get; set; }
|
||||
public string NewConfigurationName { get; set; }
|
||||
|
||||
public string Title => "Surface Editor";
|
||||
|
||||
private void RgbServiceOnDeviceLoaded(object sender, DeviceEventArgs e)
|
||||
@@ -48,7 +57,7 @@ namespace Artemis.UI.ViewModels.Screens
|
||||
if (Devices.All(d => d.Device != e.Device))
|
||||
{
|
||||
var device = new RgbDeviceViewModel(e.Device) {Cursor = Cursors.Hand};
|
||||
// device.SetColorsEnabled(false);
|
||||
device.SetColorsEnabled(false);
|
||||
Devices.Add(device);
|
||||
}
|
||||
});
|
||||
@@ -60,6 +69,51 @@ namespace Artemis.UI.ViewModels.Screens
|
||||
rgbDeviceViewModel.Update();
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
protected override void OnActivate()
|
||||
{
|
||||
Task.Run(LoadSurfaceConfigurations);
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private async Task LoadSurfaceConfigurations()
|
||||
{
|
||||
SurfaceConfigurations.Clear();
|
||||
|
||||
// Get surface configs
|
||||
var configs = await _surfaceService.GetSurfaceConfigurations();
|
||||
// Populate the UI collection
|
||||
foreach (var surfaceConfiguration in configs)
|
||||
SurfaceConfigurations.Add(surfaceConfiguration);
|
||||
// Select either the first active surface or the first available surface
|
||||
SelectedSurfaceConfiguration = SurfaceConfigurations.FirstOrDefault(s => s.IsActive) ?? SurfaceConfigurations.FirstOrDefault();
|
||||
|
||||
// Create a default if there is none
|
||||
if (SelectedSurfaceConfiguration == null)
|
||||
SelectedSurfaceConfiguration = AddSurfaceConfiguration("Default");
|
||||
}
|
||||
|
||||
|
||||
public SurfaceConfiguration AddSurfaceConfiguration(string name)
|
||||
{
|
||||
var config = new SurfaceConfiguration(name);
|
||||
Execute.OnUIThread(() => SurfaceConfigurations.Add(config));
|
||||
return config;
|
||||
}
|
||||
|
||||
public void ConfigurationDialogClosing()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(NewConfigurationName))
|
||||
{
|
||||
var newConfig = AddSurfaceConfiguration(NewConfigurationName);
|
||||
SelectedSurfaceConfiguration = newConfig;
|
||||
}
|
||||
NewConfigurationName = null;
|
||||
}
|
||||
|
||||
#region Mouse actions
|
||||
|
||||
private MouseDragStatus _mouseDragStatus;
|
||||
@@ -79,6 +133,7 @@ namespace Artemis.UI.ViewModels.Screens
|
||||
others.SelectionStatus = SelectionStatus.None;
|
||||
device.SelectionStatus = SelectionStatus.Selected;
|
||||
}
|
||||
|
||||
foreach (var selectedDevice in Devices.Where(d => d.SelectionStatus == SelectionStatus.Selected))
|
||||
selectedDevice.StartMouseDrag(position);
|
||||
}
|
||||
|
||||
@@ -5,74 +5,175 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:screens="clr-namespace:Artemis.UI.ViewModels.Screens"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:models="clr-namespace:Artemis.Core.Models.Surface;assembly=Artemis.Core"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance screens:SurfaceEditorViewModel}"
|
||||
d:DesignHeight="600" d:DesignWidth="600">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary
|
||||
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.TextBlock.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.TextBlock.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="300" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock>The surface is a digital representation of your LED setup. Set this up accurately and effects will seamlessly move from one device to the other.</TextBlock>
|
||||
<Grid Name="EditorDisplayGrid"
|
||||
Grid.Row="1"
|
||||
Margin="0 5 0 0"
|
||||
MouseUp="{s:Action EditorGridMouseClick}"
|
||||
MouseDown="{s:Action EditorGridMouseClick}"
|
||||
MouseMove="{s:Action EditorGridMouseMove}">
|
||||
<Grid.Triggers>
|
||||
<EventTrigger RoutedEvent="Grid.MouseDown">
|
||||
<BeginStoryboard>
|
||||
<Storyboard TargetName="MultiSelectionPath" TargetProperty="Opacity">
|
||||
<DoubleAnimation From="0" To="1" Duration="0:0:0.1" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<EventTrigger RoutedEvent="Grid.MouseUp">
|
||||
<BeginStoryboard>
|
||||
<Storyboard TargetName="MultiSelectionPath" TargetProperty="Opacity">
|
||||
<DoubleAnimation From="1" To="0" Duration="0:0:0.2" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</Grid.Triggers>
|
||||
<Grid.Background>
|
||||
<ImageBrush TileMode="Tile" ViewportUnits="Absolute" Viewport="0,0,15,15" ImageSource="/Artemis.UI;component/Resources/tile.png" />
|
||||
</Grid.Background>
|
||||
<ItemsControl ItemsSource="{Binding Devices}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Canvas />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemContainerStyle>
|
||||
<Style TargetType="ContentPresenter">
|
||||
<Setter Property="Canvas.Left" Value="{Binding Device.Location.X}" />
|
||||
<Setter Property="Canvas.Top" Value="{Binding Device.Location.Y}" />
|
||||
</Style>
|
||||
</ItemsControl.ItemContainerStyle>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl Width="{Binding Device.Size.Width}" Height="{Binding Device.Size.Height}" s:View.Model="{Binding }" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Style="{StaticResource MaterialDesignDisplay1TextBlock}">Surface layout</TextBlock>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Style="{StaticResource MaterialDesignCaptionTextBlock}">The surface is a digital representation of your LED setup. Set this up accurately and effects will seamlessly move from one device to the other.</TextBlock>
|
||||
|
||||
<!-- Multi-selection rectangle -->
|
||||
<Path Data="{Binding SelectionRectangle}" Opacity="0" Stroke="{DynamicResource PrimaryHueLightBrush}" StrokeThickness="1" Name="MultiSelectionPath">
|
||||
<Path.Fill>
|
||||
<SolidColorBrush Color="{DynamicResource Primary400}" Opacity="0.25" />
|
||||
</Path.Fill>
|
||||
</Path>
|
||||
</Grid>
|
||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="2" Grid.Column="0" VerticalAlignment="Stretch" Margin="0,0,5,0">
|
||||
<Grid Name="EditorDisplayGrid"
|
||||
Margin="5"
|
||||
MouseUp="{s:Action EditorGridMouseClick}"
|
||||
MouseDown="{s:Action EditorGridMouseClick}"
|
||||
MouseMove="{s:Action EditorGridMouseMove}">
|
||||
<Grid.Triggers>
|
||||
<EventTrigger RoutedEvent="Grid.MouseDown">
|
||||
<BeginStoryboard>
|
||||
<Storyboard TargetName="MultiSelectionPath" TargetProperty="Opacity">
|
||||
<DoubleAnimation From="0" To="1" Duration="0:0:0.1" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<EventTrigger RoutedEvent="Grid.MouseUp">
|
||||
<BeginStoryboard>
|
||||
<Storyboard TargetName="MultiSelectionPath" TargetProperty="Opacity">
|
||||
<DoubleAnimation From="1" To="0" Duration="0:0:0.2" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</Grid.Triggers>
|
||||
<Grid.Background>
|
||||
<ImageBrush TileMode="Tile" ViewportUnits="Absolute" Viewport="0,0,15,15" ImageSource="/Artemis.UI;component/Resources/tile.png" />
|
||||
</Grid.Background>
|
||||
<ItemsControl ItemsSource="{Binding Devices}" ClipToBounds="True">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Canvas />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemContainerStyle>
|
||||
<Style TargetType="ContentPresenter">
|
||||
<Setter Property="Canvas.Left" Value="{Binding Device.Location.X}" />
|
||||
<Setter Property="Canvas.Top" Value="{Binding Device.Location.Y}" />
|
||||
</Style>
|
||||
</ItemsControl.ItemContainerStyle>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl Width="{Binding Device.Size.Width}" Height="{Binding Device.Size.Height}" s:View.Model="{Binding }" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- Multi-selection rectangle -->
|
||||
<Path Data="{Binding SelectionRectangle}" Opacity="0" Stroke="{DynamicResource PrimaryHueLightBrush}" StrokeThickness="1" Name="MultiSelectionPath">
|
||||
<Path.Fill>
|
||||
<SolidColorBrush Color="{DynamicResource Primary400}" Opacity="0.25" />
|
||||
</Path.Fill>
|
||||
</Path>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="2" Grid.Column="1" VerticalAlignment="Stretch" Margin="5,0,0,0">
|
||||
<materialDesign:DialogHost DialogClosing="{s:Action ConfirmationDialogClosing}">
|
||||
<materialDesign:DialogHost.DialogContent>
|
||||
<StackPanel Margin="16">
|
||||
<TextBlock>
|
||||
Add a new surface layout.
|
||||
</TextBlock>
|
||||
<TextBox Margin="0 8 0 0" HorizontalAlignment="Stretch" Text="{Binding NewConfigurationName}" />
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 8 0" Command="materialDesign:DialogHost.CloseDialogCommand">
|
||||
<Button.CommandParameter>
|
||||
<system:Boolean xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
True
|
||||
</system:Boolean>
|
||||
</Button.CommandParameter>
|
||||
ACCEPT
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 8 8 0" Command="materialDesign:DialogHost.CloseDialogCommand">
|
||||
<Button.CommandParameter>
|
||||
<system:Boolean xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
False
|
||||
</system:Boolean>
|
||||
</Button.CommandParameter>
|
||||
CANCEL
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</materialDesign:DialogHost.DialogContent>
|
||||
<materialDesign:DialogHost DialogClosing="{s:Action ConfigurationDialogClosing}">
|
||||
<materialDesign:DialogHost.DialogContent>
|
||||
<StackPanel Margin="16">
|
||||
<TextBlock>
|
||||
Add a new surface layout.
|
||||
</TextBlock>
|
||||
<TextBox Margin="0 8 0 0" HorizontalAlignment="Stretch" Text="{Binding NewConfigurationName}" />
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 8 0" Command="materialDesign:DialogHost.CloseDialogCommand">
|
||||
<Button.CommandParameter>
|
||||
<system:Boolean xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
True
|
||||
</system:Boolean>
|
||||
</Button.CommandParameter>
|
||||
ACCEPT
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 8 8 0" Command="materialDesign:DialogHost.CloseDialogCommand">
|
||||
<Button.CommandParameter>
|
||||
<system:Boolean xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
False
|
||||
</system:Boolean>
|
||||
</Button.CommandParameter>
|
||||
CANCEL
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</materialDesign:DialogHost.DialogContent>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox Grid.Row="0" ItemsSource="{Binding SurfaceConfigurations}">
|
||||
<ListBox.Resources>
|
||||
<DataTemplate DataType="{x:Type models:SurfaceConfiguration}">
|
||||
<TextBlock Text="{Binding Name}" ToolTip="{Binding Name}" />
|
||||
</DataTemplate>
|
||||
</ListBox.Resources>
|
||||
</ListBox>
|
||||
<materialDesign:PopupBox
|
||||
Grid.Row="0"
|
||||
Style="{StaticResource MaterialDesignMultiFloatingActionPopupBox}"
|
||||
PlacementMode="LeftAndAlignMiddles"
|
||||
UnfurlOrientation="Horizontal"
|
||||
ToolTip="Manage surface layouts"
|
||||
Margin="0 0 10 10"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom">
|
||||
<StackPanel
|
||||
Orientation="Horizontal">
|
||||
<Button ToolTip="Add a new surface layout" Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}">
|
||||
<materialDesign:PackIcon Kind="Add" />
|
||||
</Button>
|
||||
<Button ToolTip="Remove selected surface layout" Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}">
|
||||
<materialDesign:PackIcon Kind="Delete" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</materialDesign:PopupBox>
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</materialDesign:DialogHost>
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -20,6 +20,6 @@
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.12" targetFramework="net472" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.12" targetFramework="net472" />
|
||||
<package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.12" targetFramework="net472" />
|
||||
<package id="Stylet" version="1.1.22" targetFramework="net461" />
|
||||
<package id="Stylet" version="1.2.0" targetFramework="net472" />
|
||||
<package id="System.ValueTuple" version="4.5.0" targetFramework="net472" />
|
||||
</packages>
|
||||
Reference in new issue
Block a user