diff --git a/src/Artemis.UI.Avalonia.Shared/Controls/DeviceVisualizer.cs b/src/Artemis.UI.Avalonia.Shared/Controls/DeviceVisualizer.cs index 9c6a592e1..af925a65d 100644 --- a/src/Artemis.UI.Avalonia.Shared/Controls/DeviceVisualizer.cs +++ b/src/Artemis.UI.Avalonia.Shared/Controls/DeviceVisualizer.cs @@ -263,7 +263,7 @@ namespace Artemis.UI.Avalonia.Shared.Controls ArtemisDevice? device = Device; Task.Run(() => { - if (device.Layout?.Image == null || !File.Exists(device.Layout.Image.LocalPath)) + if (device.Layout?.Image == null || !File.Exists(device.Layout.Image.LocalPath)) return; try @@ -291,6 +291,9 @@ namespace Artemis.UI.Avalonia.Shared.Controls /// protected override Size MeasureOverride(Size availableSize) { + if (_deviceBounds.Width <= 0 || _deviceBounds.Height <= 0) + return new Size(0, 0); + double availableWidth = double.IsInfinity(availableSize.Width) ? _deviceBounds.Width : availableSize.Width; double availableHeight = double.IsInfinity(availableSize.Height) ? _deviceBounds.Height : availableSize.Height; double bestRatio = Math.Min(availableWidth / _deviceBounds.Width, availableHeight / _deviceBounds.Height); diff --git a/src/Artemis.UI.Avalonia.Shared/Services/Builders/ContentDialogBuilder.cs b/src/Artemis.UI.Avalonia.Shared/Services/Builders/ContentDialogBuilder.cs index e082e189e..9cf160b09 100644 --- a/src/Artemis.UI.Avalonia.Shared/Services/Builders/ContentDialogBuilder.cs +++ b/src/Artemis.UI.Avalonia.Shared/Services/Builders/ContentDialogBuilder.cs @@ -22,7 +22,7 @@ namespace Artemis.UI.Avalonia.Shared.Services.Builders _parent = parent; _contentDialog = new ContentDialog { - CloseButtonText = "CLose" + CloseButtonText = "Close" }; } @@ -76,11 +76,11 @@ namespace Artemis.UI.Avalonia.Shared.Services.Builders return this; } - public ContentDialogBuilder WithViewModel(out T viewModel, params (string name, object value)[] parameters) + public ContentDialogBuilder WithViewModel(out T viewModel, params (string name, object value)[] parameters) where T : ViewModelBase { IParameter[] paramsArray = parameters.Select(kv => new ConstructorArgument(kv.name, kv.value)).Cast().ToArray(); viewModel = _kernel.Get(paramsArray); - _contentDialog.Content = _kernel.Get(); + _contentDialog.Content = viewModel; return this; } diff --git a/src/Artemis.UI.Avalonia/Screens/Device/ViewModels/DeviceDetectInputViewModel.cs b/src/Artemis.UI.Avalonia/Screens/Device/ViewModels/DeviceDetectInputViewModel.cs index 636532a0f..8eb1de492 100644 --- a/src/Artemis.UI.Avalonia/Screens/Device/ViewModels/DeviceDetectInputViewModel.cs +++ b/src/Artemis.UI.Avalonia/Screens/Device/ViewModels/DeviceDetectInputViewModel.cs @@ -1,15 +1,60 @@ -using Artemis.Core; +using System; +using System.Linq; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Avalonia.Shared; +using Artemis.UI.Avalonia.Shared.Services.Builders; +using Artemis.UI.Avalonia.Shared.Services.Interfaces; +using ReactiveUI; +using RGB.NET.Core; namespace Artemis.UI.Avalonia.Screens.Device.ViewModels { - public class DeviceDetectInputViewModel + public class DeviceDetectInputViewModel : ActivatableViewModelBase { - public DeviceDetectInputViewModel(ArtemisDevice device) + private readonly IInputService _inputService; + private readonly INotificationService _notificationService; + private readonly IRgbService _rgbService; + private readonly ListLedGroup _ledGroup; + + public DeviceDetectInputViewModel(ArtemisDevice device, IInputService inputService, INotificationService notificationService, IRgbService rgbService) { + _inputService = inputService; + _notificationService = notificationService; + _rgbService = rgbService; + Device = device; + + // Create a LED group way at the top + _ledGroup = new ListLedGroup(_rgbService.Surface, Device.Leds.Select(l => l.RgbLed)) + { + Brush = new SolidColorBrush(new Color(255, 255, 0)), + ZIndex = 999 + }; + + this.WhenActivated(disposables => + { + Observable.FromEventPattern(x => _inputService.DeviceIdentified += x, x => _inputService.DeviceIdentified -= x) + .Subscribe(_ => InputServiceOnDeviceIdentified()) + .DisposeWith(disposables); + + Disposable.Create(() => _ledGroup.Detach()).DisposeWith(disposables); + }); } public ArtemisDevice Device { get; } + public bool IsMouse => Device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Mouse; + public bool MadeChanges { get; set; } + + private void InputServiceOnDeviceIdentified() + { + _notificationService.CreateNotification() + .WithMessage($"{Device.RgbDevice.DeviceInfo.DeviceName} identified 😁") + .WithSeverity(NotificationSeverity.Success) + .Show(); + } } } \ No newline at end of file diff --git a/src/Artemis.UI.Avalonia/Screens/Device/ViewModels/DeviceSettingsViewModel.cs b/src/Artemis.UI.Avalonia/Screens/Device/ViewModels/DeviceSettingsViewModel.cs index a5347253c..f724a068f 100644 --- a/src/Artemis.UI.Avalonia/Screens/Device/ViewModels/DeviceSettingsViewModel.cs +++ b/src/Artemis.UI.Avalonia/Screens/Device/ViewModels/DeviceSettingsViewModel.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Reactive; +using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; using Artemis.UI.Avalonia.Ninject.Factories; @@ -19,6 +20,7 @@ namespace Artemis.UI.Avalonia.Screens.Device.ViewModels private readonly IDeviceVmFactory _deviceVmFactory; private readonly IRgbService _rgbService; private readonly IWindowService _windowService; + private bool _togglingDevice; public DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel, IDeviceService deviceService, IWindowService windowService, IDeviceVmFactory deviceVmFactory, IRgbService rgbService) @@ -33,6 +35,8 @@ namespace Artemis.UI.Avalonia.Screens.Device.ViewModels Type = Device.DeviceType.ToString().Humanize(); Name = Device.RgbDevice.DeviceInfo.Model; Manufacturer = Device.RgbDevice.DeviceInfo.Manufacturer; + + DetectInput = ReactiveCommand.CreateFromTask(ExecuteDetectInput, this.WhenAnyValue(vm => vm.CanDetectInput)); } public ArtemisDevice Device { get; } @@ -42,6 +46,7 @@ namespace Artemis.UI.Avalonia.Screens.Device.ViewModels public string Manufacturer { get; } public bool CanDetectInput => Device.DeviceType is RGBDeviceType.Keyboard or RGBDeviceType.Mouse; + public ReactiveCommand DetectInput { get; } public bool IsDeviceEnabled { @@ -49,6 +54,12 @@ namespace Artemis.UI.Avalonia.Screens.Device.ViewModels set => Dispatcher.UIThread.InvokeAsync(async () => await UpdateIsDeviceEnabled(value)); } + public bool TogglingDevice + { + get => _togglingDevice; + set => this.RaiseAndSetIfChanged(ref _togglingDevice, value); + } + public void IdentifyDevice() { _deviceService.IdentifyDevice(Device); @@ -59,13 +70,15 @@ namespace Artemis.UI.Avalonia.Screens.Device.ViewModels Utilities.OpenFolder(Device.DeviceProvider.Plugin.Directory.FullName); } - public async Task DetectInput() + private async Task ExecuteDetectInput() { if (!CanDetectInput) return; await _windowService.CreateContentDialog() + .WithTitle($"{Device.RgbDevice.DeviceInfo.DeviceName} - Detect input") .WithViewModel(out var viewModel, ("device", Device)) + .WithCloseButtonText("Cancel") .ShowAsync(); if (viewModel.MadeChanges) @@ -79,16 +92,28 @@ namespace Artemis.UI.Avalonia.Screens.Device.ViewModels private async Task UpdateIsDeviceEnabled(bool value) { - if (!value) - value = !await _devicesTabViewModel.ShowDeviceDisableDialog(); + if (TogglingDevice) + return; - if (value) - _rgbService.EnableDevice(Device); - else - _rgbService.DisableDevice(Device); + try + { + TogglingDevice = true; - this.RaisePropertyChanged(nameof(IsDeviceEnabled)); - SaveDevice(); + if (!value) + value = !await _devicesTabViewModel.ShowDeviceDisableDialog(); + + if (value) + _rgbService.EnableDevice(Device); + else + _rgbService.DisableDevice(Device); + + this.RaisePropertyChanged(nameof(IsDeviceEnabled)); + SaveDevice(); + } + finally + { + TogglingDevice = false; + } } private void SaveDevice() diff --git a/src/Artemis.UI.Avalonia/Screens/Device/Views/DeviceDetectInputView.axaml b/src/Artemis.UI.Avalonia/Screens/Device/Views/DeviceDetectInputView.axaml index 71c6948f7..113d6d9b8 100644 --- a/src/Artemis.UI.Avalonia/Screens/Device/Views/DeviceDetectInputView.axaml +++ b/src/Artemis.UI.Avalonia/Screens/Device/Views/DeviceDetectInputView.axaml @@ -2,7 +2,28 @@ 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" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" + mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="1050" x:Class="Artemis.UI.Avalonia.Screens.Device.Views.DeviceDetectInputView"> - Welcome to Avalonia! - + + + + Press a button/key on your device that is currently showing a yellow color. + + + + + + + This will teach Artemis to associate button/key presses with this specific device. + + + \ No newline at end of file diff --git a/src/Artemis.UI.Avalonia/Screens/Device/Views/DeviceDetectInputView.axaml.cs b/src/Artemis.UI.Avalonia/Screens/Device/Views/DeviceDetectInputView.axaml.cs index ed56b2222..cd60e9293 100644 --- a/src/Artemis.UI.Avalonia/Screens/Device/Views/DeviceDetectInputView.axaml.cs +++ b/src/Artemis.UI.Avalonia/Screens/Device/Views/DeviceDetectInputView.axaml.cs @@ -1,10 +1,10 @@ -using Avalonia; -using Avalonia.Controls; +using Artemis.UI.Avalonia.Screens.Device.ViewModels; using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; namespace Artemis.UI.Avalonia.Screens.Device.Views { - public partial class DeviceDetectInputView : UserControl + public class DeviceDetectInputView : ReactiveUserControl { public DeviceDetectInputView() { @@ -16,4 +16,4 @@ namespace Artemis.UI.Avalonia.Screens.Device.Views AvaloniaXamlLoader.Load(this); } } -} +} \ No newline at end of file diff --git a/src/Artemis.UI.Avalonia/Screens/Settings/Tabs/Views/DevicesTabView.axaml b/src/Artemis.UI.Avalonia/Screens/Settings/Tabs/Views/DevicesTabView.axaml index fe66685ba..1d97437af 100644 --- a/src/Artemis.UI.Avalonia/Screens/Settings/Tabs/Views/DevicesTabView.axaml +++ b/src/Artemis.UI.Avalonia/Screens/Settings/Tabs/Views/DevicesTabView.axaml @@ -13,7 +13,7 @@ Disabling a device will cause it to stop updating. Some SDKs will even go back to using manufacturer lighting (Artemis restart may be required). - +