//
// 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();
}
}