Workshop - Added layout finder

This commit is contained in:
RobertBeekman committed 2024-05-02 20:02:12 +02:00
1 parent c18f542a61
commit 957bfde0af
35 files changed
+598 -127

No files matched your search

@@ -42,16 +42,7 @@
</Ellipse>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{CompiledBinding Name}" Margin="0 4 0 0"></TextBlock>
<TextBlock Grid.Column="1" Grid.Row="1" Text="{CompiledBinding Email}"></TextBlock>
<controls:HyperlinkButton
IsVisible="{CompiledBinding AllowLogout}"
Grid.Column="1"
Grid.Row="2"
Margin="-8 4 0 0"
Padding="6 4"
Click="Signout_OnClick">
Sign out
</controls:HyperlinkButton>
<controls:HyperlinkButton
IsVisible="{CompiledBinding AllowLogout}"
Grid.Column="1"
@@ -61,6 +52,15 @@
Click="Manage_OnClick">
Manage account
</controls:HyperlinkButton>
<controls:HyperlinkButton
IsVisible="{CompiledBinding AllowLogout}"
Grid.Column="1"
Grid.Row="2"
Margin="-8 4 0 0"
Padding="6 4"
Click="Signout_OnClick">
Sign out
</controls:HyperlinkButton>
</Grid>
</Flyout>
</Ellipse.ContextFlyout>
@@ -15,8 +15,8 @@
</Styles>
</UserControl.Styles>
<Grid ColumnDefinitions="300,*" RowDefinitions="Auto,*,Auto">
<StackPanel Grid.Column="0" Grid.RowSpan="3" Margin="0 0 10 0" VerticalAlignment="Top">
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,*,Auto">
<StackPanel Grid.Column="0" Grid.RowSpan="3" Margin="0 0 10 0" VerticalAlignment="Top" Width="300" IsVisible="{CompiledBinding ShowCategoryFilter}">
<Border Classes="card" VerticalAlignment="Stretch">
<StackPanel>
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">Categories</TextBlock>
@@ -54,6 +54,7 @@ public partial class EntryListViewModel : RoutableScreen
this.WhenActivated(d =>
{
InputViewModel.WhenAnyValue(vm => vm.Search).Skip(1).Throttle(TimeSpan.FromMilliseconds(200)).Subscribe(_ => Reset()).DisposeWith(d);
InputViewModel.WhenAnyValue(vm => vm.SortBy).Skip(1).Throttle(TimeSpan.FromMilliseconds(200)).Subscribe(_ => Reset()).DisposeWith(d);
CategoriesViewModel.WhenAnyValue(vm => vm.CategoryFilters).Skip(1).Subscribe(_ => Reset()).DisposeWith(d);
});
@@ -71,6 +72,7 @@ public partial class EntryListViewModel : RoutableScreen
public CategoriesViewModel CategoriesViewModel { get; }
public EntryListInputViewModel InputViewModel { get; }
public bool ShowCategoryFilter { get; set; } = true;
public EntryType? EntryType { get; set; }
public ReadOnlyObservableCollection<EntryListItemViewModel> Entries { get; }
@@ -1,24 +0,0 @@
<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:dialogs="clr-namespace:Artemis.UI.Screens.Workshop.Layout.Dialogs"
xmlns:surfaceEditor="clr-namespace:Artemis.UI.Screens.SurfaceEditor"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Layout.Dialogs.DeviceSelectionDialogView"
x:DataType="dialogs:DeviceSelectionDialogViewModel">
<StackPanel>
<TextBlock>
Select the devices on which you would like to apply the downloaded layout.
</TextBlock>
<ItemsControl Name="EffectDescriptorsList" ItemsSource="{CompiledBinding Devices}" Margin="0 10 0 0">
<ItemsControl.DataTemplates>
<DataTemplate DataType="{x:Type surfaceEditor:ListDeviceViewModel}">
<CheckBox IsChecked="{CompiledBinding IsSelected}">
<TextBlock Text="{CompiledBinding Device.RgbDevice.DeviceInfo.DeviceName}"></TextBlock>
</CheckBox>
</DataTemplate>
</ItemsControl.DataTemplates>
</ItemsControl>
</StackPanel>
</UserControl>
@@ -1,11 +0,0 @@
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Workshop.Layout.Dialogs;
public partial class DeviceSelectionDialogView : ReactiveUserControl<DeviceSelectionDialogViewModel>
{
public DeviceSelectionDialogView()
{
InitializeComponent();
}
}
@@ -1,44 +0,0 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories;
using Artemis.UI.Screens.SurfaceEditor;
using Artemis.UI.Shared;
using Artemis.WebClient.Workshop.Models;
using Artemis.WebClient.Workshop.Providers;
using Artemis.WebClient.Workshop.Services;
using ReactiveUI;
namespace Artemis.UI.Screens.Workshop.Layout.Dialogs;
public class DeviceSelectionDialogViewModel : ContentDialogViewModelBase
{
private readonly IDeviceService _deviceService;
private readonly WorkshopLayoutProvider _layoutProvider;
public DeviceSelectionDialogViewModel(List<ArtemisDevice> devices, InstalledEntry entry, ISurfaceVmFactory surfaceVmFactory, IDeviceService deviceService, WorkshopLayoutProvider layoutProvider)
{
_deviceService = deviceService;
_layoutProvider = layoutProvider;
Entry = entry;
Devices = new ObservableCollection<ListDeviceViewModel>(devices.Select(surfaceVmFactory.ListDeviceViewModel));
Apply = ReactiveCommand.Create(ExecuteApply);
}
public InstalledEntry Entry { get; }
public ObservableCollection<ListDeviceViewModel> Devices { get; }
public ReactiveCommand<Unit, Unit> Apply { get; }
private void ExecuteApply()
{
foreach (ListDeviceViewModel listDeviceViewModel in Devices.Where(d => d.IsSelected))
{
_layoutProvider.ConfigureDevice(listDeviceViewModel.Device, Entry);
_deviceService.SaveDevice(listDeviceViewModel.Device);
_deviceService.LoadDeviceLayout(listDeviceViewModel.Device);
}
}
}
@@ -31,13 +31,14 @@ public partial class LayoutInfoViewModel : ValidatableViewModelBase
IWindowService windowService,
IPluginManagementService pluginManagementService)
{
ArtemisDevice? device = deviceService.Devices.FirstOrDefault(d => d.Layout == layout);
_windowService = windowService;
_vendor = layout.RgbLayout.Vendor;
_model = layout.RgbLayout.Model;
_vendor = device?.RgbDevice.DeviceInfo.Manufacturer ?? layout.RgbLayout.Vendor;
_model = device?.RgbDevice.DeviceInfo.Model ?? layout.RgbLayout.Model;
DeviceProvider? deviceProvider = deviceService.Devices.FirstOrDefault(d => d.Layout == layout)?.DeviceProvider;
if (deviceProvider != null)
_deviceProviderId = deviceProvider.Plugin.Guid;
if (device != null)
_deviceProviderId = device.DeviceProvider.Plugin.Guid;
_deviceProviders = this.WhenAnyValue(vm => vm.DeviceProviderId)
.Select(id => pluginManagementService.GetAllPlugins().FirstOrDefault(p => p.Guid == id)?.Features.Select(f => f.Name))
@@ -0,0 +1,25 @@
<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.Layout"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Layout.LayoutListDefaultView"
x:DataType="layout:LayoutListDefaultViewModel">
<Grid ColumnDefinitions="400,*">
<Border Grid.Column="0" Classes="card" Margin="0 0 10 0" VerticalAlignment="Top">
<StackPanel>
<DockPanel>
<Button DockPanel.Dock="Right"
Content="Auto-install layouts"
Command="{CompiledBinding LayoutFinderViewModel.SearchAll}"
ToolTip.Tip="Search layouts and if found install them automatically"/>
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">Detected devices</TextBlock>
</DockPanel>
<Border Classes="card-separator" />
<ContentControl Content="{CompiledBinding LayoutFinderViewModel}"></ContentControl>
</StackPanel>
</Border>
<ContentControl Grid.Column="1" Content="{CompiledBinding EntryListViewModel}"></ContentControl>
</Grid>
</UserControl>
@@ -0,0 +1,14 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Workshop.Layout;
public partial class LayoutListDefaultView : ReactiveUserControl<LayoutListDefaultViewModel>
{
public LayoutListDefaultView()
{
InitializeComponent();
}
}
@@ -0,0 +1,20 @@
using Artemis.UI.Screens.Workshop.Entries.List;
using Artemis.UI.Screens.Workshop.LayoutFinder;
using Artemis.UI.Shared.Routing;
using Artemis.WebClient.Workshop;
namespace Artemis.UI.Screens.Workshop.Layout;
public class LayoutListDefaultViewModel : RoutableScreen
{
public LayoutListDefaultViewModel(LayoutFinderViewModel layoutFinderViewModel, EntryListViewModel entryListViewModel)
{
LayoutFinderViewModel = layoutFinderViewModel;
EntryListViewModel = entryListViewModel;
EntryListViewModel.EntryType = EntryType.Layout;
EntryListViewModel.ShowCategoryFilter = false;
}
public LayoutFinderViewModel LayoutFinderViewModel { get; }
public EntryListViewModel EntryListViewModel { get; }
}
@@ -7,11 +7,10 @@ namespace Artemis.UI.Screens.Workshop.Layout;
public class LayoutListViewModel : RoutableHostScreen<RoutableScreen>
{
private readonly EntryListViewModel _entryListViewModel;
public override RoutableScreen DefaultScreen => _entryListViewModel;
public override RoutableScreen DefaultScreen { get; }
public LayoutListViewModel(EntryListViewModel entryListViewModel)
public LayoutListViewModel(LayoutListDefaultViewModel defaultViewModel)
{
_entryListViewModel = entryListViewModel;
_entryListViewModel.EntryType = EntryType.Layout;
DefaultScreen = defaultViewModel;
}
}
@@ -0,0 +1,73 @@
<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:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:layoutFinder="clr-namespace:Artemis.UI.Screens.Workshop.LayoutFinder"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia.ProgressRing"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="55"
x:Class="Artemis.UI.Screens.Workshop.LayoutFinder.LayoutFinderDeviceView"
x:DataType="layoutFinder:LayoutFinderDeviceViewModel">
<Grid RowDefinitions="Auto,Auto" ColumnDefinitions="55,*,Auto">
<Border Grid.Column="0" Grid.RowSpan="2" Width="50" Height="50" Margin="5 0 10 5" IsVisible="{CompiledBinding HasLayout}" >
<shared:DeviceVisualizer Device="{CompiledBinding Device}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
RenderOptions.BitmapInterpolationMode="MediumQuality"/>
</Border>
<avalonia:MaterialIcon Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
IsVisible="{CompiledBinding !HasLayout}"
Kind="{CompiledBinding DeviceIcon}"
Width="50"
Height="40"
Margin="5 5 10 10"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.Model}" VerticalAlignment="Bottom" />
<TextBlock Grid.Column="1" Grid.Row="1" Classes="subtitle" VerticalAlignment="Top">
<Run Text="{CompiledBinding Device.RgbDevice.DeviceInfo.Manufacturer}"></Run>
<Run>-</Run>
<Run Text="{CompiledBinding Device.RgbDevice.DeviceInfo.DeviceType}"></Run>
</TextBlock>
<Panel Grid.Column="2" Grid.Row="0" Grid.RowSpan="2" IsVisible="{CompiledBinding !HasLayout}">
<controls:ProgressRing IsVisible="{CompiledBinding Searching}"
IsIndeterminate="True"
BorderThickness="2"
Width="25"
Height="25"
PreserveAspect="False"
Margin="0 0 0 0"
VerticalAlignment="Center"/>
<Panel IsVisible="{CompiledBinding !Searching}">
<avalonia:MaterialIcon IsVisible="{CompiledBinding Entry, Converter={x:Static ObjectConverters.IsNull}}"
Width="28"
Height="28"
Kind="MultiplyCircle"
Foreground="#D64848"
ToolTip.Tip="No layout found"/>
<avalonia:MaterialIcon IsVisible="{CompiledBinding Entry, Converter={x:Static ObjectConverters.IsNotNull}}"
Width="28"
Height="28"
Kind="CloudCheck"
Foreground="{DynamicResource SystemAccentColorLight1}"
ToolTip.Tip="Layout found and installed"/>
</Panel>
</Panel>
<avalonia:MaterialIcon Grid.Column="2"
Grid.Row="0"
Grid.RowSpan="2"
IsVisible="{CompiledBinding HasLayout}"
Width="28"
Height="28"
Kind="CheckCircle"
Foreground="{DynamicResource SystemAccentColorLight1}"
ToolTip.Tip="Using existing layout"/>
</Grid>
</UserControl>
@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.Workshop.LayoutFinder;
public partial class LayoutFinderDeviceView : UserControl
{
public LayoutFinderDeviceView()
{
InitializeComponent();
}
}
@@ -0,0 +1,159 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Utilities;
using Artemis.WebClient.Workshop;
using Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
using Artemis.WebClient.Workshop.Models;
using Artemis.WebClient.Workshop.Providers;
using Artemis.WebClient.Workshop.Services;
using Material.Icons;
using Material.Icons.Avalonia;
using PropertyChanged.SourceGenerator;
using StrawberryShake;
namespace Artemis.UI.Screens.Workshop.LayoutFinder;
public partial class LayoutFinderDeviceViewModel : ViewModelBase
{
private readonly IWorkshopClient _client;
private readonly IDeviceService _deviceService;
private readonly IWorkshopService _workshopService;
private readonly WorkshopLayoutProvider _layoutProvider;
private readonly EntryInstallationHandlerFactory _factory;
[Notify] private bool _searching;
[Notify] private bool _hasLayout;
[Notify] private IEntrySummary? _entry;
[Notify] private IRelease? _release;
[Notify] private string? _logicalLayout;
[Notify] private string? _physicalLayout;
public LayoutFinderDeviceViewModel(ArtemisDevice device,
IWorkshopClient client,
IDeviceService deviceService,
IWorkshopService workshopService,
WorkshopLayoutProvider layoutProvider,
EntryInstallationHandlerFactory factory)
{
_client = client;
_deviceService = deviceService;
_workshopService = workshopService;
_layoutProvider = layoutProvider;
_factory = factory;
Device = device;
DeviceIcon = DetermineDeviceIcon();
HasLayout = Device.Layout != null && !Device.Layout.IsDefaultLayout;
}
public ArtemisDevice Device { get; }
public MaterialIconKind DeviceIcon { get; }
public async Task Search()
{
if (HasLayout)
return;
try
{
Searching = true;
Task delayTask = Task.Delay(400);
if (Device.DeviceType == RGB.NET.Core.RGBDeviceType.Keyboard)
await SearchKeyboardLayout();
else
await SearchLayout();
if (Entry != null && Release != null)
await InstallAndApplyEntry(Entry, Release);
await delayTask;
}
finally
{
Searching = false;
HasLayout = Device.Layout != null && !Device.Layout.IsDefaultLayout;
}
}
private async Task SearchKeyboardLayout()
{
IOperationResult<ISearchKeyboardLayoutResult> result = await _client.SearchKeyboardLayout.ExecuteAsync(
Device.DeviceProvider.Plugin.Guid,
Device.RgbDevice.DeviceInfo.Model,
Device.RgbDevice.DeviceInfo.Manufacturer,
Device.LogicalLayout,
Enum.Parse<Artemis.WebClient.Workshop.KeyboardLayoutType>(Device.PhysicalLayout.ToString(), true));
Entry = result.Data?.SearchKeyboardLayout?.Entry;
Release = result.Data?.SearchKeyboardLayout?.Entry.LatestRelease;
LogicalLayout = result.Data?.SearchKeyboardLayout?.LogicalLayout;
PhysicalLayout = result.Data?.SearchKeyboardLayout?.PhysicalLayout.ToString();
}
private async Task SearchLayout()
{
IOperationResult<ISearchLayoutResult> result = await _client.SearchLayout.ExecuteAsync(
Enum.Parse<RGBDeviceType>(Device.DeviceType.ToString(), true),
Device.DeviceProvider.Plugin.Guid,
Device.RgbDevice.DeviceInfo.Model,
Device.RgbDevice.DeviceInfo.Manufacturer);
Entry = result.Data?.SearchLayout?.Entry;
Release = result.Data?.SearchLayout?.Entry.LatestRelease;
LogicalLayout = null;
PhysicalLayout = null;
}
private async Task InstallAndApplyEntry(IEntrySummary entry, IRelease release)
{
// Try a local install first
InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(entry.Id);
if (installedEntry == null)
{
IEntryInstallationHandler installationHandler = _factory.CreateHandler(EntryType.Layout);
EntryInstallResult result = await installationHandler.InstallAsync(entry, release, new Progress<StreamProgress>(), CancellationToken.None);
installedEntry = result.Entry;
}
if (installedEntry != null)
{
_layoutProvider.ConfigureDevice(Device, installedEntry);
_deviceService.SaveDevice(Device);
_deviceService.LoadDeviceLayout(Device);
}
}
private MaterialIconKind DetermineDeviceIcon()
{
return Device.DeviceType switch
{
RGB.NET.Core.RGBDeviceType.None => MaterialIconKind.QuestionMarkCircle,
RGB.NET.Core.RGBDeviceType.Keyboard => MaterialIconKind.Keyboard,
RGB.NET.Core.RGBDeviceType.Mouse => MaterialIconKind.Mouse,
RGB.NET.Core.RGBDeviceType.Headset => MaterialIconKind.Headset,
RGB.NET.Core.RGBDeviceType.Mousepad => MaterialIconKind.TextureBox,
RGB.NET.Core.RGBDeviceType.LedStripe => MaterialIconKind.LightStrip,
RGB.NET.Core.RGBDeviceType.LedMatrix => MaterialIconKind.DrawingBox,
RGB.NET.Core.RGBDeviceType.Mainboard => MaterialIconKind.Chip,
RGB.NET.Core.RGBDeviceType.GraphicsCard => MaterialIconKind.GraphicsProcessingUnit,
RGB.NET.Core.RGBDeviceType.DRAM => MaterialIconKind.Memory,
RGB.NET.Core.RGBDeviceType.HeadsetStand => MaterialIconKind.HeadsetDock,
RGB.NET.Core.RGBDeviceType.Keypad => MaterialIconKind.Keypad,
RGB.NET.Core.RGBDeviceType.Fan => MaterialIconKind.Fan,
RGB.NET.Core.RGBDeviceType.Speaker => MaterialIconKind.Speaker,
RGB.NET.Core.RGBDeviceType.Cooler => MaterialIconKind.FreezingPoint,
RGB.NET.Core.RGBDeviceType.Monitor => MaterialIconKind.DesktopWindows,
RGB.NET.Core.RGBDeviceType.LedController => MaterialIconKind.LedStripVariant,
RGB.NET.Core.RGBDeviceType.GameController => MaterialIconKind.MicrosoftXboxController,
RGB.NET.Core.RGBDeviceType.Unknown => MaterialIconKind.QuestionMarkCircle,
RGB.NET.Core.RGBDeviceType.All => MaterialIconKind.QuestionMarkCircle,
_ => MaterialIconKind.QuestionMarkCircle
};
}
}
@@ -0,0 +1,27 @@
<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:layoutFinder="clr-namespace:Artemis.UI.Screens.Workshop.LayoutFinder"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.LayoutFinder.LayoutFinderView"
x:DataType="layoutFinder:LayoutFinderViewModel">
<ItemsControl ItemsSource="{CompiledBinding DeviceViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="layoutFinder:LayoutFinderDeviceViewModel">
<StackPanel Classes="device-view-model-container">
<!-- Your existing item template goes here -->
<ContentControl Content="{CompiledBinding}"/>
<Border Classes="card-separator" Name="Separator" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Styles>
<Styles>
<Style Selector="ContentPresenter:nth-last-child(1) Border#Separator">
<Setter Property="IsVisible" Value="False" />
</Style>
</Styles>
</ItemsControl.Styles>
</ItemsControl>
</UserControl>
@@ -0,0 +1,14 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Workshop.LayoutFinder;
public partial class LayoutFinderView : ReactiveUserControl<LayoutFinderViewModel>
{
public LayoutFinderView()
{
InitializeComponent();
}
}
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared;
using DynamicData;
using PropertyChanged.SourceGenerator;
using ReactiveUI;
using RGB.NET.Core;
using Serilog;
namespace Artemis.UI.Screens.Workshop.LayoutFinder;
public partial class LayoutFinderViewModel : ActivatableViewModelBase
{
private readonly ILogger _logger;
private readonly SourceList<IRGBDeviceInfo> _devices;
[Notify] private ReadOnlyObservableCollection<LayoutFinderDeviceViewModel> _deviceViewModels;
public LayoutFinderViewModel(ILogger logger, IDeviceService deviceService, Func<ArtemisDevice, LayoutFinderDeviceViewModel> getDeviceViewModel)
{
_logger = logger;
SearchAll = ReactiveCommand.CreateFromTask(ExecuteSearchAll);
this.WhenActivated((CompositeDisposable _) =>
{
IEnumerable<LayoutFinderDeviceViewModel> deviceGroups = deviceService.EnabledDevices.Select(getDeviceViewModel);
DeviceViewModels = new ReadOnlyObservableCollection<LayoutFinderDeviceViewModel>(new ObservableCollection<LayoutFinderDeviceViewModel>(deviceGroups));
});
}
public ReactiveCommand<Unit, Unit> SearchAll { get; }
private async Task ExecuteSearchAll()
{
foreach (LayoutFinderDeviceViewModel deviceViewModel in DeviceViewModels)
{
try
{
await deviceViewModel.Search();
}
catch (Exception e)
{
_logger.Error(e, "Failed to search for layout on device {Device}", deviceViewModel.Device);
}
}
}
}
@@ -24,6 +24,11 @@
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>
<TextBlock TextWrapping="Wrap" Classes="warning" Margin="0 10 0 0">
<Run>Ensure you enter the model and vendor</Run>
<Run FontWeight="Bold">exactly</Run>
<Run>as detected on the device by Artemis.</Run>
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="1"