A src/PacketLogger/Models/Filters/FilterProfile.cs => src/PacketLogger/Models/Filters/FilterProfile.cs +50 -0
@@ 0,0 1,50 @@
+//
+// FilterProfile.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.Collections.ObjectModel;
+using System.ComponentModel;
+using CommunityToolkit.Mvvm.ComponentModel;
+using ReactiveUI;
+
+namespace PacketLogger.Models.Filters;
+
+/// <summary>
+/// A filter profile.
+/// </summary>
+public class FilterProfile : ObservableObject
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FilterProfile"/> class.
+ /// </summary>
+ /// <param name="isDefault">Whether this profile is a default profile.</param>
+ public FilterProfile(bool isDefault)
+ {
+ IsDefault = isDefault;
+ Name = "New filter";
+ RecvFilterEntry = new FilterProfileEntry();
+ SendFilterEntry = new FilterProfileEntry();
+ }
+
+ /// <summary>
+ /// Gets whether this profile is a default profile.
+ /// </summary>
+ public bool IsDefault { get; }
+
+ /// <summary>
+ /// Gets or sets the name of the filter profile.
+ /// </summary>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the receive filter entry.
+ /// </summary>
+ public FilterProfileEntry RecvFilterEntry { get; }
+
+ /// <summary>
+ /// Gets or sets the send filter entry.
+ /// </summary>
+ public FilterProfileEntry SendFilterEntry { get; }
+}<
\ No newline at end of file
A src/PacketLogger/Models/Filters/FilterProfileEntry.cs => src/PacketLogger/Models/Filters/FilterProfileEntry.cs +40 -0
@@ 0,0 1,40 @@
+//
+// FilterProfileEntry.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.Collections.ObjectModel;
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace PacketLogger.Models.Filters;
+
+/// <summary>
+/// Receive of send entry of a <see cref="FilterProfile"/>.
+/// </summary>
+public class FilterProfileEntry : ObservableObject
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FilterProfileEntry"/> class.
+ /// </summary>
+ public FilterProfileEntry()
+ {
+ Active = true;
+ Filters = new ObservableCollection<FilterCreator.FilterData>();
+ }
+
+ /// <summary>
+ /// Gets or sets whether the filter is active.
+ /// </summary>
+ public bool Active { get; set; }
+
+ /// <summary>
+ /// Gets or sets whether the filters should whitelist or blacklist.
+ /// </summary>
+ public bool Whitelist { get; set; }
+
+ /// <summary>
+ /// Gets or sets the filters list.
+ /// </summary>
+ public ObservableCollection<FilterCreator.FilterData> Filters { get; }
+}<
\ No newline at end of file
A src/PacketLogger/Models/Filters/FilterProfiles.cs => src/PacketLogger/Models/Filters/FilterProfiles.cs +90 -0
@@ 0,0 1,90 @@
+//
+// FilterProfiles.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.Collections.ObjectModel;
+using System.Reactive.Linq;
+
+namespace PacketLogger.Models.Filters;
+
+/// <summary>
+/// A collection of <see cref="FilterProfile"/>s.
+/// </summary>
+public class FilterProfiles
+{
+ private bool _defaultFilterEnabled;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FilterProfiles"/> class.
+ /// </summary>
+ public FilterProfiles()
+ {
+ DefaultProfile = new FilterProfile(true)
+ {
+ Name = "Default"
+ };
+
+ AllProfiles = new ObservableCollection<FilterProfile>();
+ SelectableProfiles = new ObservableCollection<FilterProfile>();
+
+ AllProfiles.Add(DefaultProfile);
+ }
+
+ /// <summary>
+ /// Gets or sets whether the default filter is enabled.
+ /// </summary>
+ public bool DefaultFilterEnabled
+ {
+ get => _defaultFilterEnabled;
+ set
+ {
+ if (!_defaultFilterEnabled && value)
+ {
+ SelectableProfiles.Insert(0, DefaultProfile);
+ }
+ else if (_defaultFilterEnabled && !value)
+ {
+ SelectableProfiles.Remove(DefaultProfile);
+ }
+
+ _defaultFilterEnabled = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the default filter.
+ /// </summary>
+ public FilterProfile DefaultProfile { get; }
+
+ /// <summary>
+ /// Gets or sets the collection of profiles.
+ /// </summary>
+ public ObservableCollection<FilterProfile> SelectableProfiles { get; }
+
+ /// <summary>
+ /// Gets or sets the collection of profiles.
+ /// </summary>
+ public ObservableCollection<FilterProfile> AllProfiles { get; }
+
+ /// <summary>
+ /// Add the given profile.
+ /// </summary>
+ /// <param name="profile">The profile to add.</param>
+ public void AddProfile(FilterProfile profile)
+ {
+ SelectableProfiles.Add(profile);
+ AllProfiles.Add(profile);
+ }
+
+ /// <summary>
+ /// Remove the given filter.
+ /// </summary>
+ /// <param name="profile">The profile to remove.</param>
+ public void RemoveProfile(FilterProfile profile)
+ {
+ SelectableProfiles.Remove(profile);
+ AllProfiles.Remove(profile);
+ }
+}<
\ No newline at end of file
M src/PacketLogger/PacketLogger.csproj => src/PacketLogger/PacketLogger.csproj +27 -0
@@ 42,4 42,31 @@
<PackageReference Include="Remora.Results" Version="7.2.3" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.5.1" />
</ItemGroup>
+
+ <ItemGroup>
+ <Compile Update="Views\Sender\PacketSendSubView.axaml.cs">
+ <DependentUpon>PacketSendSubView.axaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Update="Views\Sender\PacketSenderView.axaml.cs">
+ <DependentUpon>PacketSenderView.axaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Update="Views\Log\PacketLogView.axaml.cs">
+ <DependentUpon>PacketLogView.axaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Update="Views\Settings\SettingsView.axaml.cs">
+ <DependentUpon>SettingsView.axaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Update="Views\Filters\FilterChooseView.axaml.cs">
+ <DependentUpon>FilterChooseView.axaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Update="Views\Filters\FilterConfigView.axaml.cs">
+ <DependentUpon>FilterConfigView.axaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ </ItemGroup>
</Project>
M src/PacketLogger/ViewModels/DockFactory.cs => src/PacketLogger/ViewModels/DockFactory.cs +8 -0
@@ 16,6 16,7 @@ using Dock.Model.Mvvm.Controls;
using NosSmooth.Comms.Local;
using NosSmooth.Core.Stateful;
using PacketLogger.Models;
+using PacketLogger.Models.Filters;
using PacketLogger.Models.Packets;
using PacketLogger.Views;
using ReactiveUI;
@@ 29,6 30,7 @@ namespace PacketLogger.ViewModels;
public class DockFactory : Factory, IDisposable
{
private readonly StatefulRepository _repository;
+ private readonly FilterProfiles _filterProfiles;
private readonly ObservableCollection<IPacketProvider> _providers;
private readonly NostaleProcesses _processes;
private readonly CommsInjector _injector;
@@ 39,18 41,21 @@ public class DockFactory : Factory, IDisposable
/// <summary>
/// Initializes a new instance of the <see cref="DockFactory"/> class.
/// </summary>
+ /// <param name="filterProfiles">The filter profiles.</param>
/// <param name="providers">The providers.</param>
/// <param name="processes">The nostale processes.</param>
/// <param name="injector">The communications injector.</param>
/// <param name="repository">The repository.</param>
public DockFactory
(
+ FilterProfiles filterProfiles,
ObservableCollection<IPacketProvider> providers,
NostaleProcesses processes,
CommsInjector injector,
StatefulRepository repository
)
{
+ _filterProfiles = filterProfiles;
_providers = providers;
_processes = processes;
_repository = repository;
@@ 96,6 101,7 @@ public class DockFactory : Factory, IDisposable
var document = new DocumentViewModel
(
+ _filterProfiles,
_injector,
_repository,
_providers,
@@ 138,6 144,7 @@ public class DockFactory : Factory, IDisposable
var index = documentDock.VisibleDockables?.Count + 1;
var document = new DocumentViewModel
(
+ _filterProfiles,
_injector,
_repository,
_providers,
@@ 160,6 167,7 @@ public class DockFactory : Factory, IDisposable
{
var initialTab = new DocumentViewModel
(
+ _filterProfiles,
_injector,
_repository,
_providers,
M src/PacketLogger/ViewModels/DocumentViewModel.cs => src/PacketLogger/ViewModels/DocumentViewModel.cs +28 -5
@@ 25,7 25,11 @@ using NosSmooth.Core.Contracts;
using NosSmooth.Core.Extensions;
using NosSmooth.Core.Stateful;
using PacketLogger.Models;
+using PacketLogger.Models.Filters;
using PacketLogger.Models.Packets;
+using PacketLogger.ViewModels.Log;
+using PacketLogger.ViewModels.Sender;
+using PacketLogger.ViewModels.Settings;
using ReactiveUI;
using Remora.Results;
@@ 34,7 38,6 @@ namespace PacketLogger.ViewModels;
/// <inheritdoc />
public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
{
- private readonly CommsInjector _injector;
private readonly ObservableCollection<IPacketProvider> _providers;
private readonly NostaleProcesses _processes;
private readonly Action<DocumentViewModel> _onDocumentUnloaded;
@@ 45,6 48,7 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
/// <summary>
/// Initializes a new instance of the <see cref="DocumentViewModel"/> class.
/// </summary>
+ /// <param name="filterProfiles">The filter profiles.</param>
/// <param name="injector">The injector.</param>
/// <param name="repository">The repository.</param>
/// <param name="providers">The providers.</param>
@@ 53,6 57,7 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
/// <param name="onDocumentUnloaded">The action to call on document unloaded/closed.</param>
public DocumentViewModel
(
+ FilterProfiles filterProfiles,
CommsInjector injector,
StatefulRepository repository,
ObservableCollection<IPacketProvider> providers,
@@ 61,8 66,8 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
Action<DocumentViewModel> onDocumentUnloaded
)
{
+ FilterProfiles = filterProfiles;
_ctSource = new CancellationTokenSource();
- _injector = injector;
_providers = providers;
_processes = processes;
_onDocumentUnloaded = onDocumentUnloaded;
@@ 74,7 79,7 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
{
Loading = true;
_packetProvider = new DummyPacketProvider(Title);
- NestedViewModel = new PacketLogViewModel(_packetProvider);
+ NestedViewModel = new PacketLogViewModel(_packetProvider, filterProfiles);
Loaded = true;
onDocumentLoaded(this);
}
@@ 112,7 117,7 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
}
Title = Path.GetFileName(path);
- NestedViewModel = new PacketLogViewModel(provider);
+ NestedViewModel = new PacketLogViewModel(provider, filterProfiles);
Loaded = true;
Loading = false;
onDocumentLoaded(this);
@@ 171,7 176,7 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
)
.Subscribe();
- NestedViewModel = new PacketLogViewModel(provider);
+ NestedViewModel = new PacketLogViewModel(provider, filterProfiles);
Title = handshakeResponse.CharacterName ?? $"Not in game ({process.Process.Id})";
Loading = false;
Loaded = true;
@@ 192,9 197,22 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
);
ClearError = ReactiveCommand.Create(() => Error = null);
+
+ OpenSettings = ReactiveCommand.Create(
+ () =>
+ {
+ Title = "Settings";
+ NestedViewModel = new SettingsViewModel(filterProfiles);
+ Loaded = true;
+ });
}
/// <summary>
+ /// Gets the filter profiles.
+ /// </summary>
+ public FilterProfiles FilterProfiles { get; }
+
+ /// <summary>
/// Gets the processes observable.
/// </summary>
public ObservableCollection<NostaleProcess> Processes => _processes.Processes;
@@ 259,6 277,11 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
/// </summary>
public ReactiveCommand<NostaleProcess, Unit> OpenProcess { get; }
+ /// <summary>
+ /// Get open settings command.
+ /// </summary>
+ public ReactiveCommand<Unit, Unit> OpenSettings { get; }
+
/// <inheritdoc />
public override bool OnClose()
{
A src/PacketLogger/ViewModels/Filters/FilterChooseViewModel.cs => src/PacketLogger/ViewModels/Filters/FilterChooseViewModel.cs +129 -0
@@ 0,0 1,129 @@
+//
+// FilterChooseViewModel.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.Generic;
+using System.Reactive.Disposables;
+using DynamicData.Binding;
+using PacketLogger.Models.Filters;
+using ReactiveUI;
+
+namespace PacketLogger.ViewModels.Filters;
+
+/// <summary>
+/// A view model for filter choose view.
+/// </summary>
+public class FilterChooseViewModel : ViewModelBase, IDisposable
+{
+ private FilterProfile _currentProfile = null!;
+ private IDisposable? _cleanUp;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FilterChooseViewModel"/> class.
+ /// </summary>
+ /// <param name="currentProfile">The current filter profile.</param>
+ public FilterChooseViewModel(FilterProfile currentProfile)
+ {
+ RecvFilterSelected = true;
+ CurrentProfile = currentProfile;
+ CurrentFilter = CreateSendRecvFilter();
+ }
+
+ /// <summary>
+ /// Gets the current profile.
+ /// </summary>
+ public FilterProfile CurrentProfile
+ {
+ get => _currentProfile;
+ set
+ {
+ _currentProfile = value;
+ RecvEntryViewModel = new FilterEntryViewModel(_currentProfile.RecvFilterEntry);
+ SendEntryViewModel = new FilterEntryViewModel(_currentProfile.SendFilterEntry);
+
+ var recvWhenAny = _currentProfile.RecvFilterEntry.WhenAnyPropertyChanged("Active", "Whitelist")
+ .Subscribe((e) => OnChange());
+
+ var sendWhenAny = _currentProfile.SendFilterEntry.WhenAnyPropertyChanged("Active", "Whitelist")
+ .Subscribe((e) => OnChange());
+
+ var recvFilters = _currentProfile.RecvFilterEntry.Filters.ObserveCollectionChanges()
+ .Subscribe((e) => OnChange());
+
+ var sendFilters = _currentProfile.SendFilterEntry.Filters.ObserveCollectionChanges()
+ .Subscribe((e) => OnChange());
+
+ _cleanUp?.Dispose();
+ _cleanUp = new CompositeDisposable(recvWhenAny, sendWhenAny, recvFilters, sendFilters);
+ OnChange();
+ }
+ }
+
+ /// <summary>
+ /// Gets the current recv entry view model.
+ /// </summary>
+ public FilterEntryViewModel RecvEntryViewModel { get; private set; } = null!;
+
+ /// <summary>
+ /// Gets the current send entry view model.
+ /// </summary>
+ public FilterEntryViewModel SendEntryViewModel { get; private set; } = null!;
+
+ /// <summary>
+ /// Gets whether the send filter is currently selected.
+ /// </summary>
+ public bool SendFilterSelected { get; set; }
+
+ /// <summary>
+ /// Gets whether the recv filter is currently selected.
+ /// </summary>
+ public bool RecvFilterSelected { get; set; }
+
+ /// <summary>
+ /// Gets the currently selected filter.
+ /// </summary>
+ public IFilter CurrentFilter { get; private set; }
+
+ private void OnChange()
+ {
+ CurrentFilter = CreateSendRecvFilter();
+ }
+
+ /// <summary>
+ /// Create a filter out of the chosen filters.
+ /// </summary>
+ /// <returns>The created filter.</returns>
+ public IFilter CreateSendRecvFilter()
+ {
+ IFilter recvFilter = CreateCompound(RecvEntryViewModel.Entry);
+ IFilter sendFilter = CreateCompound(SendEntryViewModel.Entry);
+
+ return new SendRecvFilter(sendFilter, recvFilter);
+ }
+
+ private IFilter CreateCompound(FilterProfileEntry filterEntry)
+ {
+ if (!filterEntry.Active)
+ {
+ return new CompoundFilter(true);
+ }
+
+ List<IFilter> filters = new List<IFilter>();
+
+ foreach (var filter in filterEntry.Filters)
+ {
+ filters.Add(FilterCreator.BuildFilter(filter.Type, filter.Value));
+ }
+
+ return new CompoundFilter(!filterEntry.Whitelist, filters.ToArray());
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ _cleanUp?.Dispose();
+ }
+}<
\ No newline at end of file
A src/PacketLogger/ViewModels/Filters/FilterConfigViewModel.cs => src/PacketLogger/ViewModels/Filters/FilterConfigViewModel.cs +43 -0
@@ 0,0 1,43 @@
+//
+// FilterConfigViewModel.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 PacketLogger.Models.Filters;
+
+namespace PacketLogger.ViewModels.Filters;
+
+/// <summary>
+/// A view model for FilterConfigView.
+/// </summary>
+public class FilterConfigViewModel : ViewModelBase
+{
+ private readonly FilterProfile _filterProfile;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FilterConfigViewModel"/> class.
+ /// </summary>
+ /// <param name="filterProfile">The filter profile to show and configure.</param>
+ public FilterConfigViewModel(FilterProfile filterProfile)
+ {
+ _filterProfile = filterProfile;
+ RecvEntryViewModel = new FilterEntryViewModel(filterProfile.RecvFilterEntry);
+ SendEntryViewModel = new FilterEntryViewModel(filterProfile.SendFilterEntry);
+ }
+
+ /// <summary>
+ /// Gets the filter profile.
+ /// </summary>
+ public FilterProfile Profile => _filterProfile;
+
+ /// <summary>
+ /// Gets the recv entry view model.
+ /// </summary>
+ public FilterEntryViewModel RecvEntryViewModel { get; }
+
+ /// <summary>
+ /// Gets the send entry view model.
+ /// </summary>
+ public FilterEntryViewModel SendEntryViewModel { get; }
+}<
\ No newline at end of file
R src/PacketLogger/ViewModels/PacketLogFilterViewModel.cs => src/PacketLogger/ViewModels/Filters/FilterEntryViewModel.cs +18 -37
@@ 1,30 1,28 @@
//
-// PacketLogFilterViewModel.cs
+// FilterEntryViewModel.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.ObjectModel;
using System.Reactive;
-using Avalonia;
-using Avalonia.Input.Platform;
-using DynamicData;
-using Microsoft.VisualBasic;
using PacketLogger.Models.Filters;
using ReactiveUI;
-namespace PacketLogger.ViewModels;
+namespace PacketLogger.ViewModels.Filters;
-/// <inheritdoc />
-public class PacketLogFilterViewModel : ViewModelBase, IDisposable
+/// <summary>
+/// A view model for FilterEntryView.
+/// </summary>
+public class FilterEntryViewModel : ViewModelBase
{
/// <summary>
- /// Initializes a new instance of the <see cref="PacketLogFilterViewModel"/> class.
+ /// Initializes a new instance of the <see cref="FilterEntryViewModel"/> class.
/// </summary>
- public PacketLogFilterViewModel()
+ /// <param name="entry">The profile entry.</param>
+ public FilterEntryViewModel(FilterProfileEntry entry)
{
- Filters = new ObservableCollection<FilterCreator.FilterData>();
+ NewFilterType = FilterCreator.FilterType.PacketHeader;
+ Entry = entry;
RemoveCurrent = ReactiveCommand.Create
(
() =>
@@ 32,14 30,14 @@ public class PacketLogFilterViewModel : ViewModelBase, IDisposable
var selected = SelectedFilter;
if (selected is not null)
{
- var selectedIndex = Filters.IndexOf(selected);
- SelectedFilter = Filters.Count > selectedIndex + 1 ? Filters[selectedIndex + 1] : null;
+ var selectedIndex = Entry.Filters.IndexOf(selected);
+ SelectedFilter = Entry.Filters.Count > selectedIndex + 1 ? Entry.Filters[selectedIndex + 1] : null;
if (SelectedFilter is null && selectedIndex > 0)
{
- SelectedFilter = Filters[selectedIndex - 1];
+ SelectedFilter = Entry.Filters[selectedIndex - 1];
}
- Filters.Remove(selected);
+ Entry.Filters.Remove(selected);
}
}
);
@@ 51,7 49,7 @@ public class PacketLogFilterViewModel : ViewModelBase, IDisposable
if (!string.IsNullOrEmpty(NewFilter))
{
var newFilter = new FilterCreator.FilterData(NewFilterType, NewFilter);
- Filters.Add(newFilter);
+ Entry.Filters.Add(newFilter);
NewFilter = string.Empty;
SelectedFilter = newFilter;
}
@@ 60,9 58,9 @@ public class PacketLogFilterViewModel : ViewModelBase, IDisposable
}
/// <summary>
- /// Gets or sets whether the filters should whitelist or blacklist.
+ /// Gets the filter profile entry associated with this view model.
/// </summary>
- public bool Whitelist { get; set; }
+ public FilterProfileEntry Entry { get; }
/// <summary>
/// Gets or sets the currently selected filter.
@@ 70,11 68,6 @@ public class PacketLogFilterViewModel : ViewModelBase, IDisposable
public FilterCreator.FilterData? SelectedFilter { get; set; }
/// <summary>
- /// Gets or sets the filters list.
- /// </summary>
- public ObservableCollection<FilterCreator.FilterData> Filters { get; }
-
- /// <summary>
/// Gets or sets the type of the new filter to add.
/// </summary>
public FilterCreator.FilterType NewFilterType { get; set; }
@@ 93,16 86,4 @@ public class PacketLogFilterViewModel : ViewModelBase, IDisposable
/// Gets the command to add new filter.
/// </summary>
public ReactiveCommand<Unit, Unit> AddNew { get; }
-
- /// <summary>
- /// Gets or sets whether the filter is active.
- /// </summary>
- public bool Active { get; set; } = true;
-
- /// <inheritdoc />
- public void Dispose()
- {
- RemoveCurrent.Dispose();
- AddNew.Dispose();
- }
}=
\ No newline at end of file
M src/PacketLogger/ViewModels/MainWindowViewModel.cs => src/PacketLogger/ViewModels/MainWindowViewModel.cs +12 -0
@@ 12,6 12,7 @@ using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Concurrency;
+using System.Reactive.Linq;
using System.Reflection;
using Avalonia;
using Avalonia.Controls;
@@ 25,7 26,9 @@ using NosSmooth.PacketSerializer.Abstractions.Attributes;
using NosSmooth.PacketSerializer.Extensions;
using NosSmooth.PacketSerializer.Packets;
using PacketLogger.Models;
+using PacketLogger.Models.Filters;
using PacketLogger.Models.Packets;
+using PacketLogger.ViewModels.Log;
using ReactiveUI;
namespace PacketLogger.ViewModels;
@@ 43,6 46,7 @@ public class MainWindowViewModel : ViewModelBase, INotifyPropertyChanged
{
var services = new ServiceCollection()
.AddLogging(b => b.ClearProviders().AddConsole())
+ .AddSingleton<FilterProfiles>()
.AddSingleton<DockFactory>()
.AddSingleton<NostaleProcesses>()
.AddSingleton<ObservableCollection<IPacketProvider>>(_ => Providers)
@@ 164,6 168,9 @@ public class MainWindowViewModel : ViewModelBase, INotifyPropertyChanged
OpenEmpty = ReactiveCommand.Create
(() => _factory.CreateLoadedDocument(doc => doc.OpenDummy.Execute(Unit.Default)));
+ OpenSettings = ReactiveCommand.Create
+ (() => _factory.CreateLoadedDocument(doc => doc.OpenSettings.Execute(Unit.Default)));
+
Connect = ReactiveCommand.Create<IList>
(process => _factory.CreateLoadedDocument(doc => doc.OpenProcess.Execute((NostaleProcess)process[0]!)));
@@ 231,4 238,9 @@ public class MainWindowViewModel : ViewModelBase, INotifyPropertyChanged
/// Gets the command that opens a new tab.
/// </summary>
public ReactiveCommand<Unit, Unit> NewTab { get; }
+
+ /// <summary>
+ /// Gets the command used for opening settings.
+ /// </summary>
+ public ReactiveCommand<Unit, Unit> OpenSettings { get; }
}=
\ No newline at end of file
D src/PacketLogger/ViewModels/PacketLogViewModel.cs => src/PacketLogger/ViewModels/PacketLogViewModel.cs +0 -267
@@ 1,267 0,0 @@
-//
-// 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.Disposables;
-using System.Reactive.Linq;
-using Avalonia;
-using Avalonia.Collections;
-using DynamicData;
-using DynamicData.Binding;
-using PacketLogger.Models;
-using PacketLogger.Models.Filters;
-using PacketLogger.Models.Packets;
-using ReactiveUI;
-using Reloaded.Memory.Kernel32;
-
-namespace PacketLogger.ViewModels;
-
-/// <inheritdoc />
-public class PacketLogViewModel : ViewModelBase, IDisposable
-{
- private readonly ReadOnlyObservableCollection<PacketInfo> _packets;
- private readonly IDisposable _cleanUp;
- private bool _logReceived = true;
- private bool _logSent = true;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="PacketLogViewModel"/> class.
- /// </summary>
- /// <param name="packetProvider">The packet provider.</param>
- public PacketLogViewModel(IPacketProvider packetProvider)
- {
- Provider = packetProvider;
-
- var dynamicFilter = this.WhenValueChanged(@this => @this.CurrentFilter)
- .Select
- (
- filter =>
- {
- return (Func<PacketInfo, bool>)((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<IList, Unit>
- (
- list => Observable.StartAsync
- (
- async () =>
- {
- var clipboardString = string.Join
- ('\n', list.OfType<PacketInfo>().Select(x => x.PacketString));
- await Application.Current!.Clipboard!.SetTextAsync(clipboardString);
- }
- )
- );
-
- TogglePane = ReactiveCommand.Create<Unit, bool>
- (
- _ => PaneOpen = !PaneOpen
- );
-
- Clear = ReactiveCommand.Create
- (
- () => Provider.Clear()
- );
-
- SendFilter = new();
- RecvFilter = new();
-
- SendFilter.PropertyChanged += (s, e) =>
- {
- if (e.PropertyName is "Whitelist" or "Active")
- {
- CreateSendRecv();
- }
- };
- RecvFilter.PropertyChanged += (s, e) =>
- {
- if (e.PropertyName is "Whitelist" or "Active")
- {
- CreateSendRecv();
- }
- };
- SendFilter.Filters.CollectionChanged += (s, e) => { CreateSendRecv(); };
- RecvFilter.Filters.CollectionChanged += (s, e) => { CreateSendRecv(); };
- }
-
- /// <summary>
- /// Gets the send filter model.
- /// </summary>
- public PacketLogFilterViewModel SendFilter { get; }
-
- /// <summary>
- /// Gets the receive filter model.
- /// </summary>
- public PacketLogFilterViewModel RecvFilter { get; }
-
- /// <summary>
- /// Gets the currently applied filter.
- /// </summary>
- public IFilter? CurrentFilter { get; private set; }
-
- /// <summary>
- /// Gets the filtered packets.
- /// </summary>
- public ReadOnlyObservableCollection<PacketInfo> FilteredPackets => _packets;
-
- /// <summary>
- /// Gets packet provider.
- /// </summary>
- public IPacketProvider Provider { get; }
-
- /// <summary>
- /// Gets whether the pane is open.
- /// </summary>
- public bool PaneOpen { get; private set; } = true;
-
- /// <summary>
- /// Gets the toggle pane command.
- /// </summary>
- public ReactiveCommand<Unit, bool> TogglePane { get; }
-
- /// <summary>
- /// Gets command to copy packets.
- /// </summary>
- public ReactiveCommand<IList, Unit> CopyPackets { get; }
-
- /// <summary>
- /// Gets the command for clearing.
- /// </summary>
- public ReactiveCommand<Unit, Unit> Clear { get; }
-
- /// <summary>
- /// Gets or sets whether to log received packets.
- /// </summary>
- public bool LogReceived
- {
- get => _logReceived;
- set
- {
- Provider.LogReceived = value;
- _logReceived = value;
- }
- }
-
- /// <summary>
- /// Gets or sets whether to log sent packets.
- /// </summary>
- public bool LogSent
- {
- get => _logSent;
- set
- {
- Provider.LogSent = value;
- _logSent = value;
- }
- }
-
- /// <summary>
- /// Gets or sets whether to scroll to teh bottom of the grid.
- /// </summary>
- public bool Scroll { get; set; } = true;
-
- /// <summary>
- /// Gets or sets the currently selected packet.
- /// </summary>
- public object? SelectedPacket { get; set; }
-
- /// <summary>
- /// Gets empty string.
- /// </summary>
- public string Empty { get; } = string.Empty;
-
- /// <summary>
- /// Gets or sets whether the recv filter is selected.
- /// </summary>
- public bool RecvFilterSelected { get; set; }
-
- /// <summary>
- /// Gets or sets whether the send filter is selected.
- /// </summary>
- public bool SendFilterSelected { get; set; }
-
- private void CreateSendRecv()
- {
- IFilter recvFilter = CreateCompound(RecvFilter);
- IFilter sendFilter = CreateCompound(SendFilter);
-
- CurrentFilter = new SendRecvFilter(sendFilter, recvFilter);
- }
-
- private IFilter CreateCompound(PacketLogFilterViewModel packetLogFilter)
- {
- if (!packetLogFilter.Active)
- {
- return new CompoundFilter(true);
- }
-
- List<IFilter> filters = new List<IFilter>();
-
- foreach (var filter in packetLogFilter.Filters)
- {
- filters.Add(FilterCreator.BuildFilter(filter.Type, filter.Value));
- }
-
- return new CompoundFilter(!packetLogFilter.Whitelist, filters.ToArray());
- }
-
- /// <inheritdoc />
- public void Dispose()
- {
- TogglePane.Dispose();
- CopyPackets.Dispose();
- Clear.Dispose();
- Provider.Dispose();
- (Provider as CommsPacketProvider)?.CustomDispose();
- _cleanUp.Dispose();
-
- SendFilter.Dispose();
- RecvFilter.Dispose();
- }
-}>
\ No newline at end of file
R src/PacketLogger/ViewModels/PacketSendSubViewModel.cs => src/PacketLogger/ViewModels/Sender/PacketSendSubViewModel.cs +1 -1
@@ 13,7 13,7 @@ using NosSmooth.PacketSerializer.Abstractions.Attributes;
using PacketLogger.Models.Packets;
using ReactiveUI;
-namespace PacketLogger.ViewModels;
+namespace PacketLogger.ViewModels.Sender;
/// <inheritdoc />
public class PacketSendSubViewModel : ViewModelBase, IDisposable
R src/PacketLogger/ViewModels/PacketSenderViewModel.cs => src/PacketLogger/ViewModels/Sender/PacketSenderViewModel.cs +1 -3
@@ 5,12 5,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
-using System.Reactive;
using NosSmooth.PacketSerializer.Abstractions.Attributes;
using PacketLogger.Models.Packets;
-using ReactiveUI;
-namespace PacketLogger.ViewModels;
+namespace PacketLogger.ViewModels.Sender;
/// <inheritdoc />
public class PacketSenderViewModel : ViewModelBase, IDisposable
A src/PacketLogger/ViewModels/Settings/FilterSettingsViewModel.cs => src/PacketLogger/ViewModels/Settings/FilterSettingsViewModel.cs +89 -0
@@ 0,0 1,89 @@
+//
+// FilterSettingsViewModel.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.Collections.ObjectModel;
+using System.Reactive;
+using PacketLogger.Models.Filters;
+using PacketLogger.ViewModels.Filters;
+using ReactiveUI;
+
+namespace PacketLogger.ViewModels.Settings;
+
+/// <inheritdoc />
+public class FilterSettingsViewModel : SettingViewModelBase
+{
+ private FilterProfile _currentFilterProfile = null!;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FilterSettingsViewModel"/> class.
+ /// </summary>
+ /// <param name="filterProfiles">The filter profiles.</param>
+ public FilterSettingsViewModel(FilterProfiles filterProfiles)
+ {
+ Profiles = filterProfiles;
+ CurrentFilterProfile = Profiles.DefaultProfile;
+
+ AddProfile = ReactiveCommand.Create(
+ () =>
+ {
+ var profile = new FilterProfile(false)
+ {
+ Name = "New profile"
+ };
+
+ Profiles.AddProfile(profile);
+ });
+
+ RemoveCurrentProfile = ReactiveCommand.Create
+ (
+ () =>
+ {
+ var currentFilterProfile = CurrentFilterProfile;
+ if (currentFilterProfile != Profiles.DefaultProfile)
+ {
+ CurrentFilterProfile = Profiles.DefaultProfile;
+ Profiles.RemoveProfile(currentFilterProfile);
+ }
+ }
+ );
+ }
+
+ /// <summary>
+ /// Gets command for adding a profile.
+ /// </summary>
+ public ReactiveCommand<Unit, Unit> AddProfile { get; }
+
+ /// <summary>
+ /// Gets command for removing the currently selected profile.
+ /// </summary>
+ public ReactiveCommand<Unit, Unit> RemoveCurrentProfile { get; }
+
+ /// <inheritdoc />
+ public override string Name => "Filters";
+
+ /// <summary>
+ /// Gets the filter profiles.
+ /// </summary>
+ public FilterProfiles Profiles { get; }
+
+ /// <summary>
+ /// Gets the current filter profile.
+ /// </summary>
+ public FilterProfile CurrentFilterProfile
+ {
+ get => _currentFilterProfile;
+ set
+ {
+ _currentFilterProfile = value;
+ CurrentFilterProfileViewModel = new FilterConfigViewModel(_currentFilterProfile);
+ }
+ }
+
+ /// <summary>
+ /// Gets the current filter profile view model.
+ /// </summary>
+ public FilterConfigViewModel CurrentFilterProfileViewModel { get; private set; } = null!;
+}<
\ No newline at end of file
A src/PacketLogger/ViewModels/Settings/SettingViewModelBase.cs => src/PacketLogger/ViewModels/Settings/SettingViewModelBase.cs +18 -0
@@ 0,0 1,18 @@
+//
+// SettingViewModelBase.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.
+
+namespace PacketLogger.ViewModels.Settings;
+
+/// <summary>
+/// A base viewmodel class for every settings tab.
+/// </summary>
+public abstract class SettingViewModelBase : ViewModelBase
+{
+ /// <summary>
+ /// Gets the name of the settings tab.
+ /// </summary>
+ public abstract string Name { get; }
+}<
\ No newline at end of file
A src/PacketLogger/ViewModels/Settings/SettingsViewModel.cs => src/PacketLogger/ViewModels/Settings/SettingsViewModel.cs +42 -0
@@ 0,0 1,42 @@
+//
+// SettingsViewModel.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.Collections.Generic;
+using System.Linq;
+using PacketLogger.Models.Filters;
+
+namespace PacketLogger.ViewModels.Settings;
+
+/// <inheritdoc />
+public class SettingsViewModel : ViewModelBase
+{
+ private readonly FilterProfiles _filterProfiles;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SettingsViewModel"/> class.
+ /// </summary>
+ /// <param name="filterProfiles">The filter profiles.</param>
+ public SettingsViewModel(FilterProfiles filterProfiles)
+ {
+ _filterProfiles = filterProfiles;
+ Settings = new[]
+ {
+ new FilterSettingsViewModel(filterProfiles)
+ };
+
+ SelectedSetting = Settings.First();
+ }
+
+ /// <summary>
+ /// Gets the setting tabs list.
+ /// </summary>
+ public IReadOnlyList<SettingViewModelBase> Settings { get; }
+
+ /// <summary>
+ /// Gets the currently selected tab.
+ /// </summary>
+ public SettingViewModelBase SelectedSetting { get; }
+}<
\ No newline at end of file
A src/PacketLogger/Views/Filters/FilterChooseView.axaml => src/PacketLogger/Views/Filters/FilterChooseView.axaml +25 -0
@@ 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:avalonia="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia"
+ xmlns:filters="clr-namespace:PacketLogger.ViewModels.Filters"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:Class="PacketLogger.Views.Filters.FilterChooseView">
+ <Design.DataContext>
+ <filters:FilterChooseViewModel />
+ </Design.DataContext>
+ <Grid RowDefinitions="45,*">
+ <Grid Grid.Row="0" Grid.Column="0" ColumnDefinitions="24, Auto, *">
+ <TabStrip Grid.Column="2" VerticalAlignment="Center">
+ <TabStripItem IsSelected="{Binding RecvFilterSelected, Mode = TwoWay}">Recv</TabStripItem>
+ <TabStripItem IsSelected="{Binding SendFilterSelected, Mode = TwoWay}">Send</TabStripItem>
+ </TabStrip>
+ </Grid>
+
+ <Panel Grid.Row="1" Margin="0,5,0,0">
+ <ContentControl IsVisible="{Binding RecvFilterSelected}" Content="{Binding RecvEntryViewModel}"></ContentControl>
+ <ContentControl IsVisible="{Binding SendFilterSelected}" Content="{Binding SendEntryViewModel}"></ContentControl>
+ </Panel>
+ </Grid>
+</UserControl>
A src/PacketLogger/Views/Filters/FilterChooseView.axaml.cs => src/PacketLogger/Views/Filters/FilterChooseView.axaml.cs +28 -0
@@ 0,0 1,28 @@
+//
+// FilterChooseView.axaml.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 Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using PropertyChanged;
+
+namespace PacketLogger.Views.Filters;
+
+[DoNotNotify]
+public partial class FilterChooseView : UserControl
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FilterChooseView"/> class.
+ /// </summary>
+ public FilterChooseView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}<
\ No newline at end of file
A src/PacketLogger/Views/Filters/FilterConfigView.axaml => src/PacketLogger/Views/Filters/FilterConfigView.axaml +22 -0
@@ 0,0 1,22 @@
+<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:filters="clr-namespace:PacketLogger.ViewModels.Filters"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:Class="PacketLogger.Views.Filters.FilterConfigView">
+ <Design.DataContext>
+ <filters:FilterConfigViewModel />
+ </Design.DataContext>
+ <Grid RowDefinitions="Auto,Auto,*" ColumnDefinitions="Auto,*,*">
+ <TextBlock VerticalAlignment="Center" FontSize="20" Grid.Row="0" Grid.Column="0" Text="Filter Name: " />
+ <TextBox Grid.Row="0" Grid.Column="1" IsEnabled="{Binding !Profile.IsDefault}" Text="{Binding Profile.Name}" />
+
+ <TextBlock Margin="0,10,0,0" FontSize="20" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="Recv" />
+ <ContentControl Margin="10" VerticalAlignment="Stretch" MaxWidth="300" Grid.Row="2" Grid.Column="0"
+ Grid.ColumnSpan="2" Content="{Binding RecvEntryViewModel}" />
+ <TextBlock Margin="0,10,0,0" FontSize="20" Grid.Row="1" Grid.Column="2" Text="Send" />
+ <ContentControl Margin="10" VerticalAlignment="Stretch" MaxWidth="300" Grid.Row="2" Grid.Column="2"
+ Content="{Binding SendEntryViewModel}" />
+ </Grid>
+</UserControl><
\ No newline at end of file
A src/PacketLogger/Views/Filters/FilterConfigView.axaml.cs => src/PacketLogger/Views/Filters/FilterConfigView.axaml.cs +28 -0
@@ 0,0 1,28 @@
+//
+// FilterConfigView.axaml.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 Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using PropertyChanged;
+
+namespace PacketLogger.Views.Filters;
+
+[DoNotNotify]
+public partial class FilterConfigView : UserControl
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FilterConfigView"/> class.
+ /// </summary>
+ public FilterConfigView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}<
\ No newline at end of file
R src/PacketLogger/Views/PacketLogFilterView.axaml => src/PacketLogger/Views/Filters/FilterEntryView.axaml +8 -8
@@ 2,15 2,15 @@
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:vm="clr-namespace:PacketLogger.ViewModels"
- mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="450"
- x:Class="PacketLogger.Views.PacketLogFilterView">
+ xmlns:filters="clr-namespace:PacketLogger.ViewModels.Filters"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:Class="PacketLogger.Views.Filters.FilterEntryView">
<Design.DataContext>
- <vm:PacketLogFilterViewModel />
+ <filters:FilterEntryViewModel />
</Design.DataContext>
<Grid ColumnDefinitions="*,*" RowDefinitions="*, 40, 40, 40">
- <DataGrid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Items="{Binding Filters}" IsReadOnly="True"
+ <DataGrid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Items="{Binding Entry.Filters}" IsReadOnly="True"
SelectedItem="{Binding SelectedFilter}"
CanUserReorderColumns="True" CanUserSortColumns="True" CanUserResizeColumns="True">
<DataGrid.Styles>
@@ 24,11 24,11 @@
</DataGrid.Columns>
</DataGrid>
- <CheckBox Grid.Row="1" Grid.Column="0" Content="Filter active" IsChecked="{Binding Active}" />
+ <CheckBox Grid.Row="1" Grid.Column="0" Content="Filter active" IsChecked="{Binding Entry.Active}" />
<Grid Grid.Row="1" Grid.Column="1" ColumnDefinitions="*,*">
<RadioButton Grid.Column="0" Content="Wl" GroupName="WlBl"></RadioButton>
- <RadioButton Grid.Column="1" Content="Bl" GroupName="WlBl" IsChecked="{Binding !Whitelist}"></RadioButton>
+ <RadioButton Grid.Column="1" Content="Bl" GroupName="WlBl" IsChecked="{Binding !Entry.Whitelist}"></RadioButton>
</Grid>
<TextBox VerticalAlignment="Center" Margin="0, 0, 5, 0" Height="30" Grid.Row="2" Grid.Column="0"
@@ 43,4 43,4 @@
<Button HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" Margin="5, 0, 0,0" Grid.Row="3"
Grid.Column="1" Content="Add" Command="{Binding AddNew}" IsDefault="True" />
</Grid>
-</UserControl>>
\ No newline at end of file
+</UserControl>
R src/PacketLogger/Views/PacketLogFilterView.axaml.cs => src/PacketLogger/Views/Filters/FilterEntryView.axaml.cs +5 -5
@@ 1,5 1,5 @@
//
-// PacketLogFilterView.axaml.cs
+// FilterEntryView.axaml.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.
@@ 11,15 11,15 @@ using Avalonia.Markup.Xaml;
using PacketLogger.Models.Filters;
using PropertyChanged;
-namespace PacketLogger.Views;
+namespace PacketLogger.Views.Filters;
[DoNotNotify]
-public partial class PacketLogFilterView : UserControl
+public partial class FilterEntryView : UserControl
{
/// <summary>
- /// Initializes a new instance of the <see cref="PacketLogFilterView"/> class.
+ /// Initializes a new instance of the <see cref="FilterEntryView"/> class.
/// </summary>
- public PacketLogFilterView()
+ public FilterEntryView()
{
InitializeComponent();
this.FindControl<ComboBox>("FilterType").Items = Enum.GetValues<FilterCreator.FilterType>();
M src/PacketLogger/Views/MainWindow.axaml => src/PacketLogger/Views/MainWindow.axaml +1 -0
@@ 40,6 40,7 @@
<MenuItem Header="_Save Filtered As..." Command="{Binding SaveFiltered}" />
<MenuItem Header="Save All As..." Command="{Binding SaveAll}" />
<Separator />
+ <MenuItem Header="Open Settings" Command="{Binding OpenSettings}" />
<MenuItem Header="Exit" Command="{Binding QuitApplication}" />
</MenuItem>
<MenuItem Header="_Tools">
D src/PacketLogger/Views/PacketLogView.axaml => src/PacketLogger/Views/PacketLogView.axaml +0 -98
@@ 1,98 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:vm="clr-namespace:PacketLogger.ViewModels"
- mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
- x:Class="PacketLogger.Views.PacketLogView"
- xmlns:i="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia"
- xmlns:converters="clr-namespace:PacketLogger.Converters"
- xmlns:views="clr-namespace:PacketLogger.Views"
- xmlns:packets="clr-namespace:PacketLogger.Models.Packets"
- xmlns:packetLogger="clr-namespace:PacketLogger"
- x:Name="UserControl">
- <UserControl.Resources>
- <converters:PacketSourceConverter x:Key="packetSourceConverter" />
- </UserControl.Resources>
- <Design.DataContext>
- <vm:PacketLogViewModel />
- </Design.DataContext>
- <SplitView OpenPaneLength="300" IsPaneOpen="{Binding PaneOpen, Mode = TwoWay}" DisplayMode="CompactInline"
- PanePlacement="Right">
- <SplitView.Pane>
- <Grid Width="280" HorizontalAlignment="Left"
- ColumnDefinitions="*" RowDefinitions="*,80" Margin="10">
- <Grid Grid.Row="0" RowDefinitions="45,*">
- <Grid Grid.Row="0" Grid.Column="0" ColumnDefinitions="24, Auto, *">
- <Button Margin="0,1,0,0" VerticalContentAlignment="Stretch"
- HorizontalContentAlignment="Stretch" Width="22" Height="22"
- Command="{Binding TogglePane}">
- <Grid>
- <i:Icon Value="mdi-menu-left" Height="22" Width="22" Margin="0,0,2,0"
- IsVisible="{Binding !PaneOpen}" />
- <i:Icon Value="mdi-menu-right" Height="22" Width="22" IsVisible="{Binding PaneOpen}" />
- </Grid>
- </Button>
- <TextBlock VerticalAlignment="Center" Grid.Column="1" FontSize="30" Text="Filter"
- Margin="5,0,0,0" />
- <TabStrip Grid.Column="2" VerticalAlignment="Center">
- <TabStripItem IsSelected="{Binding RecvFilterSelected, Mode = TwoWay}">Recv</TabStripItem>
- <TabStripItem IsSelected="{Binding SendFilterSelected, Mode = TwoWay}">Send</TabStripItem>
- </TabStrip>
- </Grid>
-
- <Panel Grid.Row="1" Margin="0,5,0,0">
- <ContentControl IsVisible="{Binding RecvFilterSelected}" Content="{Binding RecvFilter}"></ContentControl>
- <ContentControl IsVisible="{Binding SendFilterSelected}" Content="{Binding SendFilter}"></ContentControl>
- </Panel>
- </Grid>
-
- <Grid Grid.Row="1" RowDefinitions="40,40" ColumnDefinitions="140,140">
- <CheckBox Grid.Row="0" Grid.Column="0" Content="Log received" IsChecked="{Binding LogReceived}" />
- <CheckBox Grid.Row="0" Grid.Column="1" Content="Log sent" IsChecked="{Binding LogSent}" />
- <CheckBox Grid.Row="1" Grid.Column="0" Content="Scroll" IsChecked="{Binding Scroll}" />
- <Button Grid.Row="1" Grid.Column="1" Content="Clear" HorizontalAlignment="Stretch"
- HorizontalContentAlignment="Center" Command="{Binding Clear}" />
- </Grid>
- </Grid>
- </SplitView.Pane>
-
- <ListBox Items="{Binding FilteredPackets}"
- x:Name="PacketsLog"
- SelectionMode="Multiple"
- SelectedItem="{Binding SelectedPacket, Mode=TwoWay}"
- VerticalAlignment="Stretch"
- SelectionChanged="PacketsLog_OnSelectionChanged">
- <ListBox.Styles>
- <Style Selector="ListBoxItem">
- <Setter Property="Padding" Value="1" />
- </Style>
- <Style Selector="TextBlock">
- <Setter Property="FontSize" Value="12" />
- </Style>
- </ListBox.Styles>
- <ListBox.ItemTemplate>
- <DataTemplate>
- <StackPanel Height="16" Margin="0" Orientation="Horizontal">
- <TextBlock Width="60" Text="{Binding Date, StringFormat = {}{0:HH:mm:ss}}" />
- <TextBlock Width="40"
- Text="{Binding Source, Converter = {StaticResource packetSourceConverter}}">
- </TextBlock>
- <Border ToolTip.Tip="{Binding PacketString}">
- <TextBlock VerticalAlignment="Center" Text="{Binding PacketString}"
- TextTrimming="CharacterEllipsis">
- </TextBlock>
- </Border>
- </StackPanel>
- </DataTemplate>
- </ListBox.ItemTemplate>
- <ListBox.ContextMenu>
- <ContextMenu Name="PacketMenu">
- <MenuItem Header="Copy packets" Command="{Binding CopyPackets}"
- CommandParameter="{Binding ElementName=PacketsLog, Path=SelectedItems}" IsEnabled="True">
- </MenuItem>
- </ContextMenu>
- </ListBox.ContextMenu>
- </ListBox>
- </SplitView>
-</UserControl>>
\ No newline at end of file
R src/PacketLogger/Views/PacketSendSubView.axaml => src/PacketLogger/Views/Sender/PacketSendSubView.axaml +3 -2
@@ 4,13 4,14 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:PacketLogger.ViewModels"
xmlns:converters="clr-namespace:PacketLogger.Converters"
+ xmlns:sender="clr-namespace:PacketLogger.ViewModels.Sender"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
- x:Class="PacketLogger.Views.PacketSendSubView">
+ x:Class="PacketLogger.Views.Sender.PacketSendSubView">
<UserControl.Resources>
<converters:PacketSourceConverter x:Key="packetSourceConverter" />
</UserControl.Resources>
<Design.DataContext>
- <viewModels:PacketSendSubViewModel />
+ <sender:PacketSendSubViewModel />
</Design.DataContext>
<DockPanel>
R src/PacketLogger/Views/PacketSendSubView.axaml.cs => src/PacketLogger/Views/Sender/PacketSendSubView.axaml.cs +1 -2
@@ 4,12 4,11 @@
// 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 Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using PropertyChanged;
-namespace PacketLogger.Views;
+namespace PacketLogger.Views.Sender;
[DoNotNotify]
public partial class PacketSendSubView : UserControl
R src/PacketLogger/Views/PacketSenderView.axaml => src/PacketLogger/Views/Sender/PacketSenderView.axaml +3 -2
@@ 3,10 3,11 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:PacketLogger.ViewModels"
+ xmlns:sender="clr-namespace:PacketLogger.ViewModels.Sender"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
- x:Class="PacketLogger.Views.PacketSenderView">
+ x:Class="PacketLogger.Views.Sender.PacketSenderView">
<Design.DataContext>
- <viewModels:PacketSenderViewModel />
+ <sender:PacketSenderViewModel />
</Design.DataContext>
<Grid RowDefinitions="15,*,15,*" Margin="10">
<TextBlock Grid.Row="0" Text="Recv" Margin="0,0,0,5" />
R src/PacketLogger/Views/PacketSenderView.axaml.cs => src/PacketLogger/Views/Sender/PacketSenderView.axaml.cs +1 -2
@@ 4,12 4,11 @@
// 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 Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using PropertyChanged;
-namespace PacketLogger.Views;
+namespace PacketLogger.Views.Sender;
[DoNotNotify]
public partial class PacketSenderView : UserControl
A src/PacketLogger/Views/Settings/FilterSettingsView.axaml => src/PacketLogger/Views/Settings/FilterSettingsView.axaml +30 -0
@@ 0,0 1,30 @@
+<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:settings="clr-namespace:PacketLogger.ViewModels.Settings"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:Class="PacketLogger.Views.Settings.FilterSettingsView">
+ <Design.DataContext>
+ <settings:FilterSettingsViewModel />
+ </Design.DataContext>
+ <StackPanel Orientation="Horizontal">
+ <Grid RowDefinitions="*, Auto" ColumnDefinitions="*,*">
+ <ListBox Margin="0,0,0,10" Grid.ColumnSpan="2" Width="150" Items="{Binding Profiles.AllProfiles}" SelectedItem="{Binding CurrentFilterProfile}">
+ <ListBox.ItemTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Name}" />
+ </DataTemplate>
+ </ListBox.ItemTemplate>
+ </ListBox>
+
+ <Button Margin="0,0,5,0" Grid.Row="1" Grid.Column="0" Content="Remove" Command="{Binding RemoveCurrentProfile}" />
+ <Button Margin="5,0,0,0" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" Content="Add" Command="{Binding AddProfile}" />
+ </Grid>
+
+ <Grid Margin="10,0,0,0" RowDefinitions="Auto,*" VerticalAlignment="Stretch">
+ <CheckBox Grid.Row="0" Content="Enable default filter" IsChecked="{Binding Profiles.DefaultFilterEnabled}" />
+ <ContentControl Grid.Row="1" VerticalAlignment="Stretch" Margin="0,10,0,0" Content="{Binding CurrentFilterProfileViewModel}" />
+ </Grid>
+ </StackPanel>
+</UserControl><
\ No newline at end of file
R src/PacketLogger/Views/PacketLogView.axaml.cs => src/PacketLogger/Views/Settings/FilterSettingsView.axaml.cs +6 -15
@@ 1,24 1,23 @@
-//
-// PacketLogView.axaml.cs
+//
+// FilterSettingsView.axaml.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.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using PropertyChanged;
-namespace PacketLogger.Views;
+namespace PacketLogger.Views.Settings;
[DoNotNotify]
-public partial class PacketLogView : UserControl
+public partial class FilterSettingsView : UserControl
{
/// <summary>
- /// Initializes a new instance of the <see cref="PacketLogView"/> class.
+ /// Initializes a new instance of the <see cref="FilterSettingsView"/> class.
/// </summary>
- public PacketLogView()
+ public FilterSettingsView()
{
InitializeComponent();
}
@@ 27,12 26,4 @@ public partial class PacketLogView : UserControl
{
AvaloniaXamlLoader.Load(this);
}
-
- private void PacketsLog_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
- {
- if (sender is DataGrid dataGrid && dataGrid.SelectedItem is not null)
- {
- dataGrid.ScrollIntoView(dataGrid.SelectedItem, dataGrid.Columns.First());
- }
- }
}=
\ No newline at end of file
A src/PacketLogger/Views/Settings/SettingsView.axaml => src/PacketLogger/Views/Settings/SettingsView.axaml +22 -0
@@ 0,0 1,22 @@
+<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:settings="clr-namespace:PacketLogger.ViewModels.Settings"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:Class="PacketLogger.Views.Settings.SettingsView">
+ <Design.DataContext>
+ <settings:SettingsViewModel />
+ </Design.DataContext>
+ <StackPanel Orientation="Horizontal" Margin="10">
+ <ListBox Margin="10" Width="100" Items="{Binding Settings}" SelectedItem="{Binding SelectedSetting}">
+ <ListBox.ItemTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Name}"></TextBlock>
+ </DataTemplate>
+ </ListBox.ItemTemplate>
+ </ListBox>
+
+ <ContentControl VerticalAlignment="Stretch" Margin="10" Content="{Binding SelectedSetting}" />
+ </StackPanel>
+</UserControl>
A src/PacketLogger/Views/Settings/SettingsView.axaml.cs => src/PacketLogger/Views/Settings/SettingsView.axaml.cs +28 -0
@@ 0,0 1,28 @@
+//
+// SettingsView.axaml.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 Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using PropertyChanged;
+
+namespace PacketLogger.Views.Settings;
+
+[DoNotNotify]
+public partial class SettingsView : UserControl
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SettingsView"/> class.
+ /// </summary>
+ public SettingsView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}<
\ No newline at end of file