// // PacketLogViewModel.cs // // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive; using System.Reactive.Concurrency; using System.Reactive.Linq; using Avalonia; using DynamicData; using DynamicData.Binding; using PacketLogger.Models; using PacketLogger.Models.Filters; using PacketLogger.Models.Packets; using PacketLogger.ViewModels.Filters; using ReactiveUI; namespace PacketLogger.ViewModels.Log; /// public class PacketLogViewModel : ViewModelBase, IDisposable { private readonly FilterProfiles _filterProfiles; private readonly ReadOnlyObservableCollection _packets; private readonly IDisposable _cleanUp; private bool _logReceived = true; private bool _logSent = true; /// /// Initializes a new instance of the class. /// /// The packet provider. /// The filter profiles. public PacketLogViewModel(IPacketProvider packetProvider, FilterProfiles filterProfiles) { _filterProfiles = filterProfiles; FilterChoose = new FilterChooseViewModel ( filterProfiles.DefaultFilterEnabled ? filterProfiles.DefaultProfile : filterProfiles.NoProfile, filterProfiles.SelectableProfiles.Last() ); Provider = packetProvider; var dynamicFilter = FilterChoose.WhenValueChanged(x => x.CurrentFilter) .Select ( filter => { return (Func)((pi) => { if (filter is null) { return true; } return filter.Match(pi); }); } ); var packetsSubscription = Provider.Packets.Connect() .Filter(dynamicFilter) .Sort(new PacketComparer()) .Bind(out _packets) .ObserveOn(RxApp.MainThreadScheduler) .DisposeMany() .Subscribe ( _ => { if (Scroll) { RxApp.MainThreadScheduler.Schedule ( DateTimeOffset.Now.AddMilliseconds(100), () => { if (FilteredPackets.Count > 0) { SelectedPacket = FilteredPackets[^1]; } } ); } } ); _cleanUp = packetsSubscription; CopyPackets = ReactiveCommand.CreateFromObservable ( list => Observable.StartAsync ( async () => { var clipboardString = string.Join ('\n', list.OfType().Select(x => x.PacketString)); await Application.Current!.Clipboard!.SetTextAsync(clipboardString); } ) ); TogglePane = ReactiveCommand.Create ( _ => PaneOpen = !PaneOpen ); Clear = ReactiveCommand.Create ( () => Provider.Clear() ); } /// /// Gets filter profiles. /// public FilterProfiles Profiles => _filterProfiles; /// /// Gets the filtered packets. /// public ReadOnlyObservableCollection FilteredPackets => _packets; /// /// Gets packet provider. /// public IPacketProvider Provider { get; } /// /// Gets whether the pane is open. /// public bool PaneOpen { get; private set; } = true; /// /// Gets the toggle pane command. /// public ReactiveCommand TogglePane { get; } /// /// Gets command to copy packets. /// public ReactiveCommand CopyPackets { get; } /// /// Gets the command for clearing. /// public ReactiveCommand Clear { get; } /// /// Gets or sets whether to log received packets. /// public bool LogReceived { get => _logReceived; set { Provider.LogReceived = value; _logReceived = value; } } /// /// Gets or sets whether to log sent packets. /// public bool LogSent { get => _logSent; set { Provider.LogSent = value; _logSent = value; } } /// /// Gets or sets whether to scroll to teh bottom of the grid. /// public bool Scroll { get; set; } = true; /// /// Gets or sets the currently selected packet. /// public object? SelectedPacket { get; set; } /// /// Gets empty string. /// public string Empty { get; } = string.Empty; /// /// Gets the filter choose view model. /// public FilterChooseViewModel FilterChoose { get; } /// public void Dispose() { TogglePane.Dispose(); CopyPackets.Dispose(); Clear.Dispose(); Provider.Dispose(); (Provider as CommsPacketProvider)?.CustomDispose(); _cleanUp.Dispose(); } }