mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 13:28:33 +00:00
Merge branch 'development'
This commit is contained in:
commit
138d168cf2
@ -13,7 +13,10 @@ internal class LoggerFactory : ILoggerFactory
|
||||
internal static readonly ILogger Logger = new LoggerConfiguration()
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.File(Path.Combine(Constants.LogsFolder, "Artemis log-.log"),
|
||||
fileSizeLimitBytes: 5 * 1024 * 1024,
|
||||
rollOnFileSizeLimit: true,
|
||||
rollingInterval: RollingInterval.Day,
|
||||
retainedFileCountLimit: 14,
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}")
|
||||
.WriteTo.Console()
|
||||
#if DEBUG
|
||||
|
||||
@ -81,4 +81,8 @@
|
||||
<Style Selector="Run.subtitle">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="SelectableTextBlock">
|
||||
<Setter Property="SelectionBrush" Value="{DynamicResource TextControlSelectionHighlightColor}" />
|
||||
</Style>
|
||||
</Styles>
|
||||
|
||||
@ -5,6 +5,7 @@ using Artemis.UI.Screens.Debugger.DataModel;
|
||||
using Artemis.UI.Screens.Debugger.Logs;
|
||||
using Artemis.UI.Screens.Debugger.Performance;
|
||||
using Artemis.UI.Screens.Debugger.Render;
|
||||
using Artemis.UI.Screens.Debugger.Routing;
|
||||
using Artemis.UI.Services.Interfaces;
|
||||
using Artemis.UI.Shared;
|
||||
using ReactiveUI;
|
||||
@ -15,9 +16,9 @@ public class DebugViewModel : ActivatableViewModelBase, IScreen
|
||||
{
|
||||
private ViewModelBase _selectedItem;
|
||||
|
||||
public DebugViewModel(IDebugService debugService, RenderDebugViewModel render, DataModelDebugViewModel dataModel, PerformanceDebugViewModel performance, LogsDebugViewModel logs)
|
||||
public DebugViewModel(IDebugService debugService, RenderDebugViewModel render, DataModelDebugViewModel dataModel, PerformanceDebugViewModel performance, RoutingDebugViewModel routing, LogsDebugViewModel logs)
|
||||
{
|
||||
Items = new ObservableCollection<ViewModelBase> {render, dataModel, performance, logs};
|
||||
Items = new ObservableCollection<ViewModelBase> {render, dataModel, performance, routing, logs};
|
||||
_selectedItem = render;
|
||||
|
||||
this.WhenActivated(d => Disposable.Create(debugService.ClearDebugger).DisposeWith(d));
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
<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:routing="clr-namespace:Artemis.UI.Screens.Debugger.Routing"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Debugger.Routing.RoutingDebugView"
|
||||
x:DataType="routing:RoutingDebugViewModel">
|
||||
|
||||
<Grid RowDefinitions="Auto,Auto,*" ColumnDefinitions="*,Auto">
|
||||
<TextBox Grid.Row="0" Grid.Column="0" Watermark="Enter a route to navigate to" Text="{CompiledBinding Route}">
|
||||
<TextBox.KeyBindings>
|
||||
<KeyBinding Gesture="Enter" Command="{CompiledBinding Navigate}"></KeyBinding>
|
||||
</TextBox.KeyBindings>
|
||||
</TextBox>
|
||||
<Button Grid.Row="0" Grid.Column="1" Margin="5 0 0 0" Command="{CompiledBinding Navigate}">Navigate</Button>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="0 15">Navigation logs</TextBlock>
|
||||
<ScrollViewer Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Name="LogsScrollViewer" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
|
||||
<SelectableTextBlock
|
||||
Inlines="{CompiledBinding Lines}"
|
||||
FontFamily="Consolas"
|
||||
SizeChanged="Control_OnSizeChanged"
|
||||
SelectionBrush="{StaticResource TextControlSelectionHighlightColor}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@ -0,0 +1,26 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Routing;
|
||||
|
||||
public partial class RoutingDebugView : ReactiveUserControl<RoutingDebugViewModel>
|
||||
{
|
||||
public RoutingDebugView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
Dispatcher.UIThread.Post(() => LogsScrollViewer.ScrollToEnd(), DispatcherPriority.ApplicationIdle);
|
||||
}
|
||||
|
||||
private void Control_OnSizeChanged(object? sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (!(LogsScrollViewer.Extent.Height - LogsScrollViewer.Offset.Y - LogsScrollViewer.Bounds.Bottom <= 60))
|
||||
return;
|
||||
Dispatcher.UIThread.Post(() => LogsScrollViewer.ScrollToEnd(), DispatcherPriority.Normal);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
using Avalonia.Controls.Documents;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using ReactiveUI;
|
||||
using Serilog.Events;
|
||||
using Serilog.Formatting.Display;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Routing;
|
||||
|
||||
public class RoutingDebugViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly IRouter _router;
|
||||
private const int MAX_ENTRIES = 1000;
|
||||
private readonly MessageTemplateTextFormatter _formatter;
|
||||
private string? _route;
|
||||
|
||||
public RoutingDebugViewModel(IRouter router)
|
||||
{
|
||||
_router = router;
|
||||
DisplayName = "Routing";
|
||||
Navigate = ReactiveCommand.CreateFromTask(ExecuteNavigate, this.WhenAnyValue(vm => vm.Route).Select(r => !string.IsNullOrWhiteSpace(r)));
|
||||
|
||||
_formatter = new MessageTemplateTextFormatter(
|
||||
"[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}"
|
||||
);
|
||||
|
||||
foreach (LogEvent logEvent in LogStore.Events)
|
||||
AddLogEvent(logEvent);
|
||||
|
||||
this.WhenActivated(disp =>
|
||||
{
|
||||
LogStore.EventAdded += OnLogEventAdded;
|
||||
Disposable.Create(() => LogStore.EventAdded -= OnLogEventAdded).DisposeWith(disp);
|
||||
|
||||
_router.CurrentPath.Subscribe(p => Route = p).DisposeWith(disp);
|
||||
});
|
||||
}
|
||||
|
||||
public InlineCollection Lines { get; } = new();
|
||||
public ReactiveCommand<Unit, Unit> Navigate { get; }
|
||||
|
||||
public string? Route
|
||||
{
|
||||
get => _route;
|
||||
set => RaiseAndSetIfChanged(ref _route, value);
|
||||
}
|
||||
|
||||
private void OnLogEventAdded(object? sender, LogEventEventArgs e)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() => AddLogEvent(e.LogEvent));
|
||||
}
|
||||
|
||||
private void AddLogEvent(LogEvent? logEvent)
|
||||
{
|
||||
if (logEvent is null)
|
||||
return;
|
||||
if (!logEvent.Properties.TryGetValue("SourceContext", out LogEventPropertyValue? sourceContext) || sourceContext.ToString() != "\"Artemis.UI.Shared.Routing.Navigation\"")
|
||||
return;
|
||||
|
||||
using StringWriter writer = new();
|
||||
_formatter.Format(logEvent, writer);
|
||||
string line = writer.ToString();
|
||||
|
||||
Lines.Add(new Run(line.TrimEnd('\r', '\n') + '\n')
|
||||
{
|
||||
Foreground = logEvent.Level switch
|
||||
{
|
||||
LogEventLevel.Verbose => new SolidColorBrush(Colors.White),
|
||||
LogEventLevel.Debug => new SolidColorBrush(Color.FromRgb(216, 216, 216)),
|
||||
LogEventLevel.Information => new SolidColorBrush(Color.FromRgb(93, 201, 255)),
|
||||
LogEventLevel.Warning => new SolidColorBrush(Color.FromRgb(255, 177, 53)),
|
||||
LogEventLevel.Error => new SolidColorBrush(Color.FromRgb(255, 63, 63)),
|
||||
LogEventLevel.Fatal => new SolidColorBrush(Colors.Red),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
}
|
||||
});
|
||||
LimitLines();
|
||||
}
|
||||
|
||||
private void LimitLines()
|
||||
{
|
||||
if (Lines.Count > MAX_ENTRIES)
|
||||
Lines.RemoveRange(0, Lines.Count - MAX_ENTRIES);
|
||||
}
|
||||
|
||||
private async Task ExecuteNavigate(CancellationToken arg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Route != null)
|
||||
await _router.Navigate(Route.Trim());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,13 +66,11 @@ public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
Device.PropertyChanged += DeviceOnPropertyChanged;
|
||||
_coreService.FrameRendering += OnFrameRendering;
|
||||
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
_coreService.FrameRendering -= OnFrameRendering;
|
||||
Device.PropertyChanged -= DeviceOnPropertyChanged;
|
||||
Apply();
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
@ -244,10 +242,4 @@ public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
||||
using SKPaint overlayPaint = new() { Color = CurrentColor };
|
||||
e.Canvas.DrawRect(0, 0, e.Canvas.LocalClipBounds.Width, e.Canvas.LocalClipBounds.Height, overlayPaint);
|
||||
}
|
||||
|
||||
private void DeviceOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(Device.CustomLayoutPath) || e.PropertyName == nameof(Device.DisableDefaultLayout))
|
||||
Task.Run(() => _rgbService.ApplyBestDeviceLayout(Device));
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@
|
||||
<Button
|
||||
Classes="icon-button"
|
||||
HorizontalAlignment="Right"
|
||||
IsEnabled="{CompiledBinding !!DefaultLayoutPath}"
|
||||
ToolTip.Tip="Copy layout file path to clipboard"
|
||||
Click="LayoutPathButton_OnClick">
|
||||
<avalonia:MaterialIcon Kind="ContentCopy" Width="18" Height="18" />
|
||||
@ -31,12 +32,13 @@
|
||||
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
||||
<StackPanel Grid.Row="1" Grid.Column="0">
|
||||
<TextBlock Text="Image file path" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding Device.Layout.Image.LocalPath}" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding ImagePath, TargetNullValue=None}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center">
|
||||
<Button
|
||||
Classes="icon-button"
|
||||
HorizontalAlignment="Right"
|
||||
IsEnabled="{CompiledBinding !!ImagePath}"
|
||||
ToolTip.Tip="Copy image file path to clipboard"
|
||||
Click="ImagePathButton_OnClick">
|
||||
<avalonia:MaterialIcon Kind="ContentCopy" Width="18" Height="18" />
|
||||
@ -50,14 +52,14 @@
|
||||
<TextBlock Classes="subtitle" FontSize="12" Text="With this checked, Artemis will not load a layout for this device unless you specifically provide one." />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center">
|
||||
<CheckBox HorizontalAlignment="Right" Margin="0,0,-10,0" />
|
||||
<CheckBox HorizontalAlignment="Right" Margin="0,0,-10,0" IsChecked="{CompiledBinding Device.DisableDefaultLayout}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Border Classes="card-separator" />
|
||||
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
||||
<StackPanel Grid.Row="1" Grid.Column="0">
|
||||
<TextBlock Text="Custom layout path" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" Text="{CompiledBinding CustomLayoutPath}" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" Text="{CompiledBinding CustomLayoutPath, TargetNullValue=None}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<Button Content="Clear" Command="{CompiledBinding ClearCustomLayout}" IsEnabled="{CompiledBinding HasCustomLayout}" />
|
||||
|
||||
@ -16,12 +16,18 @@ public partial class DeviceLayoutTabView : ReactiveUserControl<DeviceLayoutTabVi
|
||||
|
||||
private void LayoutPathButton_OnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ViewModel?.DefaultLayoutPath is null)
|
||||
return;
|
||||
|
||||
TopLevel.GetTopLevel(this).Clipboard.SetTextAsync(ViewModel.DefaultLayoutPath);
|
||||
ViewModel.ShowCopiedNotification();
|
||||
}
|
||||
|
||||
private void ImagePathButton_OnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ViewModel?.Device?.Layout?.Image?.LocalPath is null)
|
||||
return;
|
||||
|
||||
TopLevel.GetTopLevel(this).Clipboard.SetTextAsync(ViewModel.Device.Layout.Image.LocalPath);
|
||||
ViewModel.ShowCopiedNotification();
|
||||
}
|
||||
|
||||
@ -22,42 +22,52 @@ public class DeviceLayoutTabViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly IWindowService _windowService;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IRgbService _rgbService;
|
||||
|
||||
public DeviceLayoutTabViewModel(
|
||||
IWindowService windowService,
|
||||
INotificationService notificationService,
|
||||
ICoreService coreService,
|
||||
IRgbService rgbService,
|
||||
ArtemisDevice device)
|
||||
{
|
||||
_windowService = windowService;
|
||||
_notificationService = notificationService;
|
||||
_coreService = coreService;
|
||||
_rgbService = rgbService;
|
||||
|
||||
Device = device;
|
||||
DisplayName = "Layout";
|
||||
DefaultLayoutPath = Device.DeviceProvider.LoadLayout(Device).FilePath;
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
Device.PropertyChanged += DeviceOnPropertyChanged;
|
||||
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
Device.PropertyChanged -= DeviceOnPropertyChanged;
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public ArtemisDevice Device { get; }
|
||||
|
||||
public string DefaultLayoutPath { get; }
|
||||
|
||||
public string? ImagePath => Device.Layout?.Image?.LocalPath;
|
||||
|
||||
public string CustomLayoutPath => Device.CustomLayoutPath ?? "None";
|
||||
public string CustomLayoutPath => Device.CustomLayoutPath;
|
||||
|
||||
public bool HasCustomLayout => Device.CustomLayoutPath != null;
|
||||
|
||||
private void RaiseCustomLayoutChanged()
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(CustomLayoutPath));
|
||||
this.RaisePropertyChanged(nameof(HasCustomLayout));
|
||||
}
|
||||
|
||||
public void ClearCustomLayout()
|
||||
{
|
||||
Device.CustomLayoutPath = null;
|
||||
_notificationService.CreateNotification()
|
||||
.WithMessage("Cleared imported layout.")
|
||||
.WithSeverity(NotificationSeverity.Informational);
|
||||
|
||||
RaiseCustomLayoutChanged();
|
||||
}
|
||||
|
||||
public async Task BrowseCustomLayout()
|
||||
@ -75,8 +85,6 @@ public class DeviceLayoutTabViewModel : ActivatableViewModelBase
|
||||
.WithMessage($"File loaded from {files[0]}")
|
||||
.WithSeverity(NotificationSeverity.Informational);
|
||||
}
|
||||
|
||||
RaiseCustomLayoutChanged();
|
||||
}
|
||||
|
||||
public async Task ExportLayout()
|
||||
@ -148,4 +156,10 @@ public class DeviceLayoutTabViewModel : ActivatableViewModelBase
|
||||
.WithSeverity(NotificationSeverity.Informational)
|
||||
.Show();
|
||||
}
|
||||
|
||||
private void DeviceOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName is nameof(Device.CustomLayoutPath) or nameof(Device.DisableDefaultLayout))
|
||||
Task.Run(() => _rgbService.ApplyBestDeviceLayout(Device));
|
||||
}
|
||||
}
|
||||
@ -111,7 +111,6 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
||||
}
|
||||
|
||||
public RenderProfileElement? ProfileElement => _profileElement?.Value;
|
||||
public Layer? Layer => _profileElement?.Value as Layer;
|
||||
public ILayerProperty? LayerProperty => _layerProperty?.Value;
|
||||
public bool SuspendedEditing => _suspendedEditing?.Value ?? false;
|
||||
|
||||
@ -133,26 +132,27 @@ public class PropertiesViewModel : ActivatableViewModelBase
|
||||
|
||||
private void UpdatePropertyGroups()
|
||||
{
|
||||
if (ProfileElement == null)
|
||||
RenderProfileElement? profileElement = ProfileElement;
|
||||
if (profileElement == null)
|
||||
{
|
||||
PropertyGroupViewModels.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
ObservableCollection<PropertyGroupViewModel> viewModels = new();
|
||||
if (Layer != null)
|
||||
if (profileElement is Layer layer)
|
||||
{
|
||||
// Add base VMs
|
||||
viewModels.Add(GetOrCreatePropertyViewModel(Layer.General, null, null));
|
||||
viewModels.Add(GetOrCreatePropertyViewModel(Layer.Transform, null, null));
|
||||
viewModels.Add(GetOrCreatePropertyViewModel(layer.General, null, null));
|
||||
viewModels.Add(GetOrCreatePropertyViewModel(layer.Transform, null, null));
|
||||
|
||||
// Add brush VM if the brush has properties
|
||||
if (Layer.LayerBrush?.BaseProperties != null)
|
||||
viewModels.Add(GetOrCreatePropertyViewModel(Layer.LayerBrush.BaseProperties, Layer.LayerBrush, null));
|
||||
if (layer.LayerBrush?.BaseProperties != null)
|
||||
viewModels.Add(GetOrCreatePropertyViewModel(layer.LayerBrush.BaseProperties, layer.LayerBrush, null));
|
||||
}
|
||||
|
||||
// Add effect VMs
|
||||
foreach (BaseLayerEffect layerEffect in ProfileElement.LayerEffects.OrderBy(e => e.Order))
|
||||
foreach (BaseLayerEffect layerEffect in profileElement.LayerEffects.OrderBy(e => e.Order))
|
||||
{
|
||||
if (layerEffect.BaseProperties != null)
|
||||
viewModels.Add(GetOrCreatePropertyViewModel(layerEffect.BaseProperties, null, layerEffect));
|
||||
|
||||
@ -35,11 +35,11 @@
|
||||
</controls:HyperlinkButton>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Top"
|
||||
Classes="subtitle"
|
||||
Text="{CompiledBinding Version}" />
|
||||
<SelectableTextBlock Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Top"
|
||||
Classes="subtitle"
|
||||
Text="{CompiledBinding Version}" />
|
||||
|
||||
<controls:HyperlinkButton Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
|
||||
@ -42,7 +42,15 @@ public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase
|
||||
.Select(p => p == null)
|
||||
.ToProperty(this, vm => vm.IsDisabled)
|
||||
.DisposeWith(d));
|
||||
_profileService.LoadProfileConfigurationIcon(ProfileConfiguration);
|
||||
|
||||
try
|
||||
{
|
||||
_profileService.LoadProfileConfigurationIcon(ProfileConfiguration);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored, too bad but don't crash over corrupt icons
|
||||
}
|
||||
}
|
||||
|
||||
public ProfileConfiguration ProfileConfiguration { get; }
|
||||
|
||||
@ -30,6 +30,7 @@ public class SidebarViewModel : ActivatableViewModelBase
|
||||
private readonly IWindowService _windowService;
|
||||
private ReadOnlyObservableCollection<SidebarCategoryViewModel> _sidebarCategories = new(new ObservableCollection<SidebarCategoryViewModel>());
|
||||
private SidebarScreenViewModel? _selectedScreen;
|
||||
private bool _updating;
|
||||
|
||||
public SidebarViewModel(IRouter router, IProfileService profileService, IWindowService windowService, ISidebarVmFactory sidebarVmFactory)
|
||||
{
|
||||
@ -57,7 +58,12 @@ public class SidebarViewModel : ActivatableViewModelBase
|
||||
SourceList<ProfileCategory> profileCategories = new();
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
_router.CurrentPath.WhereNotNull().Subscribe(r => SelectedScreen = SidebarScreen.GetMatch(r)).DisposeWith(d);
|
||||
_router.CurrentPath.WhereNotNull().Subscribe(r =>
|
||||
{
|
||||
_updating = true;
|
||||
SelectedScreen = SidebarScreen.GetMatch(r);
|
||||
_updating = false;
|
||||
}).DisposeWith(d);
|
||||
|
||||
Observable.FromEventPattern<ProfileCategoryEventArgs>(x => profileService.ProfileCategoryAdded += x, x => profileService.ProfileCategoryAdded -= x)
|
||||
.Subscribe(e => profileCategories.Add(e.EventArgs.ProfileCategory))
|
||||
@ -115,6 +121,9 @@ public class SidebarViewModel : ActivatableViewModelBase
|
||||
|
||||
private void NavigateToScreen(SidebarScreenViewModel sidebarScreenViewModel)
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
Dispatcher.UIThread.Invoke(async () =>
|
||||
{
|
||||
try
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<AvaloniaVersion>11.0.1</AvaloniaVersion>
|
||||
<FluentAvaloniaVersion>2.0.0</FluentAvaloniaVersion>
|
||||
<RGBDotNetVersion>2.0.0-prerelease.94</RGBDotNetVersion>
|
||||
<AvaloniaVersion>11.0.3</AvaloniaVersion>
|
||||
<FluentAvaloniaVersion>2.0.1</FluentAvaloniaVersion>
|
||||
<RGBDotNetVersion>2.0.0-prerelease.101</RGBDotNetVersion>
|
||||
<SkiaSharpVersion>2.88.3</SkiaSharpVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Loading…
x
Reference in New Issue
Block a user