From 86b762f16a33f04280b48e0c61c4585ce1e4b3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Tue, 7 Feb 2023 19:35:24 +0100 Subject: [PATCH] feat: add settings and filter profiles --- .../Models/Filters/FilterProfile.cs | 50 ++++ .../Models/Filters/FilterProfileEntry.cs | 40 +++ .../Models/Filters/FilterProfiles.cs | 90 ++++++ src/PacketLogger/PacketLogger.csproj | 27 ++ src/PacketLogger/ViewModels/DockFactory.cs | 8 + .../ViewModels/DocumentViewModel.cs | 33 ++- .../Filters/FilterChooseViewModel.cs | 129 +++++++++ .../Filters/FilterConfigViewModel.cs | 43 +++ .../FilterEntryViewModel.cs} | 55 ++-- .../ViewModels/MainWindowViewModel.cs | 12 + .../ViewModels/PacketLogViewModel.cs | 267 ------------------ .../{ => Sender}/PacketSendSubViewModel.cs | 2 +- .../{ => Sender}/PacketSenderViewModel.cs | 4 +- .../Settings/FilterSettingsViewModel.cs | 89 ++++++ .../Settings/SettingViewModelBase.cs | 18 ++ .../ViewModels/Settings/SettingsViewModel.cs | 42 +++ .../Views/Filters/FilterChooseView.axaml | 25 ++ .../Views/Filters/FilterChooseView.axaml.cs | 28 ++ .../Views/Filters/FilterConfigView.axaml | 22 ++ .../Views/Filters/FilterConfigView.axaml.cs | 28 ++ .../FilterEntryView.axaml} | 16 +- .../FilterEntryView.axaml.cs} | 10 +- src/PacketLogger/Views/MainWindow.axaml | 1 + src/PacketLogger/Views/PacketLogView.axaml | 98 ------- src/PacketLogger/Views/PacketLogView.axaml.cs | 38 --- .../{ => Sender}/PacketSendSubView.axaml | 5 +- .../{ => Sender}/PacketSendSubView.axaml.cs | 3 +- .../Views/{ => Sender}/PacketSenderView.axaml | 5 +- .../{ => Sender}/PacketSenderView.axaml.cs | 3 +- .../Views/Settings/FilterSettingsView.axaml | 30 ++ .../Settings/FilterSettingsView.axaml.cs | 29 ++ .../Views/Settings/SettingsView.axaml | 22 ++ .../Views/Settings/SettingsView.axaml.cs | 28 ++ 33 files changed, 830 insertions(+), 470 deletions(-) create mode 100644 src/PacketLogger/Models/Filters/FilterProfile.cs create mode 100644 src/PacketLogger/Models/Filters/FilterProfileEntry.cs create mode 100644 src/PacketLogger/Models/Filters/FilterProfiles.cs create mode 100644 src/PacketLogger/ViewModels/Filters/FilterChooseViewModel.cs create mode 100644 src/PacketLogger/ViewModels/Filters/FilterConfigViewModel.cs rename src/PacketLogger/ViewModels/{PacketLogFilterViewModel.cs => Filters/FilterEntryViewModel.cs} (57%) delete mode 100644 src/PacketLogger/ViewModels/PacketLogViewModel.cs rename src/PacketLogger/ViewModels/{ => Sender}/PacketSendSubViewModel.cs (98%) rename src/PacketLogger/ViewModels/{ => Sender}/PacketSenderViewModel.cs (94%) create mode 100644 src/PacketLogger/ViewModels/Settings/FilterSettingsViewModel.cs create mode 100644 src/PacketLogger/ViewModels/Settings/SettingViewModelBase.cs create mode 100644 src/PacketLogger/ViewModels/Settings/SettingsViewModel.cs create mode 100644 src/PacketLogger/Views/Filters/FilterChooseView.axaml create mode 100644 src/PacketLogger/Views/Filters/FilterChooseView.axaml.cs create mode 100644 src/PacketLogger/Views/Filters/FilterConfigView.axaml create mode 100644 src/PacketLogger/Views/Filters/FilterConfigView.axaml.cs rename src/PacketLogger/Views/{PacketLogFilterView.axaml => Filters/FilterEntryView.axaml} (84%) rename src/PacketLogger/Views/{PacketLogFilterView.axaml.cs => Filters/FilterEntryView.axaml.cs} (72%) delete mode 100644 src/PacketLogger/Views/PacketLogView.axaml delete mode 100644 src/PacketLogger/Views/PacketLogView.axaml.cs rename src/PacketLogger/Views/{ => Sender}/PacketSendSubView.axaml (91%) rename src/PacketLogger/Views/{ => Sender}/PacketSendSubView.axaml.cs (93%) rename src/PacketLogger/Views/{ => Sender}/PacketSenderView.axaml (82%) rename src/PacketLogger/Views/{ => Sender}/PacketSenderView.axaml.cs (93%) create mode 100644 src/PacketLogger/Views/Settings/FilterSettingsView.axaml create mode 100644 src/PacketLogger/Views/Settings/FilterSettingsView.axaml.cs create mode 100644 src/PacketLogger/Views/Settings/SettingsView.axaml create mode 100644 src/PacketLogger/Views/Settings/SettingsView.axaml.cs diff --git a/src/PacketLogger/Models/Filters/FilterProfile.cs b/src/PacketLogger/Models/Filters/FilterProfile.cs new file mode 100644 index 0000000..d31c7bf --- /dev/null +++ b/src/PacketLogger/Models/Filters/FilterProfile.cs @@ -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; + +/// +/// A filter profile. +/// +public class FilterProfile : ObservableObject +{ + /// + /// Initializes a new instance of the class. + /// + /// Whether this profile is a default profile. + public FilterProfile(bool isDefault) + { + IsDefault = isDefault; + Name = "New filter"; + RecvFilterEntry = new FilterProfileEntry(); + SendFilterEntry = new FilterProfileEntry(); + } + + /// + /// Gets whether this profile is a default profile. + /// + public bool IsDefault { get; } + + /// + /// Gets or sets the name of the filter profile. + /// + public string Name { get; set; } + + /// + /// Gets or sets the receive filter entry. + /// + public FilterProfileEntry RecvFilterEntry { get; } + + /// + /// Gets or sets the send filter entry. + /// + public FilterProfileEntry SendFilterEntry { get; } +} \ No newline at end of file diff --git a/src/PacketLogger/Models/Filters/FilterProfileEntry.cs b/src/PacketLogger/Models/Filters/FilterProfileEntry.cs new file mode 100644 index 0000000..562d435 --- /dev/null +++ b/src/PacketLogger/Models/Filters/FilterProfileEntry.cs @@ -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; + +/// +/// Receive of send entry of a . +/// +public class FilterProfileEntry : ObservableObject +{ + /// + /// Initializes a new instance of the class. + /// + public FilterProfileEntry() + { + Active = true; + Filters = new ObservableCollection(); + } + + /// + /// Gets or sets whether the filter is active. + /// + public bool Active { get; set; } + + /// + /// Gets or sets whether the filters should whitelist or blacklist. + /// + public bool Whitelist { get; set; } + + /// + /// Gets or sets the filters list. + /// + public ObservableCollection Filters { get; } +} \ No newline at end of file diff --git a/src/PacketLogger/Models/Filters/FilterProfiles.cs b/src/PacketLogger/Models/Filters/FilterProfiles.cs new file mode 100644 index 0000000..fa8d298 --- /dev/null +++ b/src/PacketLogger/Models/Filters/FilterProfiles.cs @@ -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; + +/// +/// A collection of s. +/// +public class FilterProfiles +{ + private bool _defaultFilterEnabled; + + /// + /// Initializes a new instance of the class. + /// + public FilterProfiles() + { + DefaultProfile = new FilterProfile(true) + { + Name = "Default" + }; + + AllProfiles = new ObservableCollection(); + SelectableProfiles = new ObservableCollection(); + + AllProfiles.Add(DefaultProfile); + } + + /// + /// Gets or sets whether the default filter is enabled. + /// + public bool DefaultFilterEnabled + { + get => _defaultFilterEnabled; + set + { + if (!_defaultFilterEnabled && value) + { + SelectableProfiles.Insert(0, DefaultProfile); + } + else if (_defaultFilterEnabled && !value) + { + SelectableProfiles.Remove(DefaultProfile); + } + + _defaultFilterEnabled = value; + } + } + + /// + /// Gets or sets the default filter. + /// + public FilterProfile DefaultProfile { get; } + + /// + /// Gets or sets the collection of profiles. + /// + public ObservableCollection SelectableProfiles { get; } + + /// + /// Gets or sets the collection of profiles. + /// + public ObservableCollection AllProfiles { get; } + + /// + /// Add the given profile. + /// + /// The profile to add. + public void AddProfile(FilterProfile profile) + { + SelectableProfiles.Add(profile); + AllProfiles.Add(profile); + } + + /// + /// Remove the given filter. + /// + /// The profile to remove. + public void RemoveProfile(FilterProfile profile) + { + SelectableProfiles.Remove(profile); + AllProfiles.Remove(profile); + } +} \ No newline at end of file diff --git a/src/PacketLogger/PacketLogger.csproj b/src/PacketLogger/PacketLogger.csproj index 12fc5a9..00488e1 100644 --- a/src/PacketLogger/PacketLogger.csproj +++ b/src/PacketLogger/PacketLogger.csproj @@ -42,4 +42,31 @@ + + + + PacketSendSubView.axaml + Code + + + PacketSenderView.axaml + Code + + + PacketLogView.axaml + Code + + + SettingsView.axaml + Code + + + FilterChooseView.axaml + Code + + + FilterConfigView.axaml + Code + + diff --git a/src/PacketLogger/ViewModels/DockFactory.cs b/src/PacketLogger/ViewModels/DockFactory.cs index 37b6426..0bfdc15 100644 --- a/src/PacketLogger/ViewModels/DockFactory.cs +++ b/src/PacketLogger/ViewModels/DockFactory.cs @@ -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 _providers; private readonly NostaleProcesses _processes; private readonly CommsInjector _injector; @@ -39,18 +41,21 @@ public class DockFactory : Factory, IDisposable /// /// Initializes a new instance of the class. /// + /// The filter profiles. /// The providers. /// The nostale processes. /// The communications injector. /// The repository. public DockFactory ( + FilterProfiles filterProfiles, ObservableCollection 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, diff --git a/src/PacketLogger/ViewModels/DocumentViewModel.cs b/src/PacketLogger/ViewModels/DocumentViewModel.cs index 523c28d..a258be3 100644 --- a/src/PacketLogger/ViewModels/DocumentViewModel.cs +++ b/src/PacketLogger/ViewModels/DocumentViewModel.cs @@ -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; /// public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable { - private readonly CommsInjector _injector; private readonly ObservableCollection _providers; private readonly NostaleProcesses _processes; private readonly Action _onDocumentUnloaded; @@ -45,6 +48,7 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable /// /// Initializes a new instance of the class. /// + /// The filter profiles. /// The injector. /// The repository. /// The providers. @@ -53,6 +57,7 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable /// The action to call on document unloaded/closed. public DocumentViewModel ( + FilterProfiles filterProfiles, CommsInjector injector, StatefulRepository repository, ObservableCollection providers, @@ -61,8 +66,8 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable Action 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,8 +197,21 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable ); ClearError = ReactiveCommand.Create(() => Error = null); + + OpenSettings = ReactiveCommand.Create( + () => + { + Title = "Settings"; + NestedViewModel = new SettingsViewModel(filterProfiles); + Loaded = true; + }); } + /// + /// Gets the filter profiles. + /// + public FilterProfiles FilterProfiles { get; } + /// /// Gets the processes observable. /// @@ -259,6 +277,11 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable /// public ReactiveCommand OpenProcess { get; } + /// + /// Get open settings command. + /// + public ReactiveCommand OpenSettings { get; } + /// public override bool OnClose() { diff --git a/src/PacketLogger/ViewModels/Filters/FilterChooseViewModel.cs b/src/PacketLogger/ViewModels/Filters/FilterChooseViewModel.cs new file mode 100644 index 0000000..710bdcc --- /dev/null +++ b/src/PacketLogger/ViewModels/Filters/FilterChooseViewModel.cs @@ -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; + +/// +/// A view model for filter choose view. +/// +public class FilterChooseViewModel : ViewModelBase, IDisposable +{ + private FilterProfile _currentProfile = null!; + private IDisposable? _cleanUp; + + /// + /// Initializes a new instance of the class. + /// + /// The current filter profile. + public FilterChooseViewModel(FilterProfile currentProfile) + { + RecvFilterSelected = true; + CurrentProfile = currentProfile; + CurrentFilter = CreateSendRecvFilter(); + } + + /// + /// Gets the current profile. + /// + 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(); + } + } + + /// + /// Gets the current recv entry view model. + /// + public FilterEntryViewModel RecvEntryViewModel { get; private set; } = null!; + + /// + /// Gets the current send entry view model. + /// + public FilterEntryViewModel SendEntryViewModel { get; private set; } = null!; + + /// + /// Gets whether the send filter is currently selected. + /// + public bool SendFilterSelected { get; set; } + + /// + /// Gets whether the recv filter is currently selected. + /// + public bool RecvFilterSelected { get; set; } + + /// + /// Gets the currently selected filter. + /// + public IFilter CurrentFilter { get; private set; } + + private void OnChange() + { + CurrentFilter = CreateSendRecvFilter(); + } + + /// + /// Create a filter out of the chosen filters. + /// + /// The created filter. + 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 filters = new List(); + + foreach (var filter in filterEntry.Filters) + { + filters.Add(FilterCreator.BuildFilter(filter.Type, filter.Value)); + } + + return new CompoundFilter(!filterEntry.Whitelist, filters.ToArray()); + } + + /// + public void Dispose() + { + _cleanUp?.Dispose(); + } +} \ No newline at end of file diff --git a/src/PacketLogger/ViewModels/Filters/FilterConfigViewModel.cs b/src/PacketLogger/ViewModels/Filters/FilterConfigViewModel.cs new file mode 100644 index 0000000..089e506 --- /dev/null +++ b/src/PacketLogger/ViewModels/Filters/FilterConfigViewModel.cs @@ -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; + +/// +/// A view model for FilterConfigView. +/// +public class FilterConfigViewModel : ViewModelBase +{ + private readonly FilterProfile _filterProfile; + + /// + /// Initializes a new instance of the class. + /// + /// The filter profile to show and configure. + public FilterConfigViewModel(FilterProfile filterProfile) + { + _filterProfile = filterProfile; + RecvEntryViewModel = new FilterEntryViewModel(filterProfile.RecvFilterEntry); + SendEntryViewModel = new FilterEntryViewModel(filterProfile.SendFilterEntry); + } + + /// + /// Gets the filter profile. + /// + public FilterProfile Profile => _filterProfile; + + /// + /// Gets the recv entry view model. + /// + public FilterEntryViewModel RecvEntryViewModel { get; } + + /// + /// Gets the send entry view model. + /// + public FilterEntryViewModel SendEntryViewModel { get; } +} \ No newline at end of file diff --git a/src/PacketLogger/ViewModels/PacketLogFilterViewModel.cs b/src/PacketLogger/ViewModels/Filters/FilterEntryViewModel.cs similarity index 57% rename from src/PacketLogger/ViewModels/PacketLogFilterViewModel.cs rename to src/PacketLogger/ViewModels/Filters/FilterEntryViewModel.cs index 8009986..2a1d915 100644 --- a/src/PacketLogger/ViewModels/PacketLogFilterViewModel.cs +++ b/src/PacketLogger/ViewModels/Filters/FilterEntryViewModel.cs @@ -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; -/// -public class PacketLogFilterViewModel : ViewModelBase, IDisposable +/// +/// A view model for FilterEntryView. +/// +public class FilterEntryViewModel : ViewModelBase { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public PacketLogFilterViewModel() + /// The profile entry. + public FilterEntryViewModel(FilterProfileEntry entry) { - Filters = new ObservableCollection(); + 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,20 +58,15 @@ public class PacketLogFilterViewModel : ViewModelBase, IDisposable } /// - /// Gets or sets whether the filters should whitelist or blacklist. + /// Gets the filter profile entry associated with this view model. /// - public bool Whitelist { get; set; } + public FilterProfileEntry Entry { get; } /// /// Gets or sets the currently selected filter. /// public FilterCreator.FilterData? SelectedFilter { get; set; } - /// - /// Gets or sets the filters list. - /// - public ObservableCollection Filters { get; } - /// /// Gets or sets the type of the new filter to add. /// @@ -93,16 +86,4 @@ public class PacketLogFilterViewModel : ViewModelBase, IDisposable /// Gets the command to add new filter. /// public ReactiveCommand AddNew { get; } - - /// - /// Gets or sets whether the filter is active. - /// - public bool Active { get; set; } = true; - - /// - public void Dispose() - { - RemoveCurrent.Dispose(); - AddNew.Dispose(); - } } \ No newline at end of file diff --git a/src/PacketLogger/ViewModels/MainWindowViewModel.cs b/src/PacketLogger/ViewModels/MainWindowViewModel.cs index 2101d48..363fe54 100644 --- a/src/PacketLogger/ViewModels/MainWindowViewModel.cs +++ b/src/PacketLogger/ViewModels/MainWindowViewModel.cs @@ -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() .AddSingleton() .AddSingleton() .AddSingleton>(_ => 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 (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. /// public ReactiveCommand NewTab { get; } + + /// + /// Gets the command used for opening settings. + /// + public ReactiveCommand OpenSettings { get; } } \ No newline at end of file diff --git a/src/PacketLogger/ViewModels/PacketLogViewModel.cs b/src/PacketLogger/ViewModels/PacketLogViewModel.cs deleted file mode 100644 index 45789cc..0000000 --- a/src/PacketLogger/ViewModels/PacketLogViewModel.cs +++ /dev/null @@ -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; - -/// -public class PacketLogViewModel : ViewModelBase, IDisposable -{ - 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. - public PacketLogViewModel(IPacketProvider packetProvider) - { - Provider = packetProvider; - - var dynamicFilter = this.WhenValueChanged(@this => @this.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() - ); - - 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(); }; - } - - /// - /// Gets the send filter model. - /// - public PacketLogFilterViewModel SendFilter { get; } - - /// - /// Gets the receive filter model. - /// - public PacketLogFilterViewModel RecvFilter { get; } - - /// - /// Gets the currently applied filter. - /// - public IFilter? CurrentFilter { get; private set; } - - /// - /// 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 or sets whether the recv filter is selected. - /// - public bool RecvFilterSelected { get; set; } - - /// - /// Gets or sets whether the send filter is selected. - /// - 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 filters = new List(); - - foreach (var filter in packetLogFilter.Filters) - { - filters.Add(FilterCreator.BuildFilter(filter.Type, filter.Value)); - } - - return new CompoundFilter(!packetLogFilter.Whitelist, filters.ToArray()); - } - - /// - 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 diff --git a/src/PacketLogger/ViewModels/PacketSendSubViewModel.cs b/src/PacketLogger/ViewModels/Sender/PacketSendSubViewModel.cs similarity index 98% rename from src/PacketLogger/ViewModels/PacketSendSubViewModel.cs rename to src/PacketLogger/ViewModels/Sender/PacketSendSubViewModel.cs index e23a7a0..6123e74 100644 --- a/src/PacketLogger/ViewModels/PacketSendSubViewModel.cs +++ b/src/PacketLogger/ViewModels/Sender/PacketSendSubViewModel.cs @@ -13,7 +13,7 @@ using NosSmooth.PacketSerializer.Abstractions.Attributes; using PacketLogger.Models.Packets; using ReactiveUI; -namespace PacketLogger.ViewModels; +namespace PacketLogger.ViewModels.Sender; /// public class PacketSendSubViewModel : ViewModelBase, IDisposable diff --git a/src/PacketLogger/ViewModels/PacketSenderViewModel.cs b/src/PacketLogger/ViewModels/Sender/PacketSenderViewModel.cs similarity index 94% rename from src/PacketLogger/ViewModels/PacketSenderViewModel.cs rename to src/PacketLogger/ViewModels/Sender/PacketSenderViewModel.cs index fe08f21..d929387 100644 --- a/src/PacketLogger/ViewModels/PacketSenderViewModel.cs +++ b/src/PacketLogger/ViewModels/Sender/PacketSenderViewModel.cs @@ -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; /// public class PacketSenderViewModel : ViewModelBase, IDisposable diff --git a/src/PacketLogger/ViewModels/Settings/FilterSettingsViewModel.cs b/src/PacketLogger/ViewModels/Settings/FilterSettingsViewModel.cs new file mode 100644 index 0000000..912d74a --- /dev/null +++ b/src/PacketLogger/ViewModels/Settings/FilterSettingsViewModel.cs @@ -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; + +/// +public class FilterSettingsViewModel : SettingViewModelBase +{ + private FilterProfile _currentFilterProfile = null!; + + /// + /// Initializes a new instance of the class. + /// + /// The filter profiles. + 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); + } + } + ); + } + + /// + /// Gets command for adding a profile. + /// + public ReactiveCommand AddProfile { get; } + + /// + /// Gets command for removing the currently selected profile. + /// + public ReactiveCommand RemoveCurrentProfile { get; } + + /// + public override string Name => "Filters"; + + /// + /// Gets the filter profiles. + /// + public FilterProfiles Profiles { get; } + + /// + /// Gets the current filter profile. + /// + public FilterProfile CurrentFilterProfile + { + get => _currentFilterProfile; + set + { + _currentFilterProfile = value; + CurrentFilterProfileViewModel = new FilterConfigViewModel(_currentFilterProfile); + } + } + + /// + /// Gets the current filter profile view model. + /// + public FilterConfigViewModel CurrentFilterProfileViewModel { get; private set; } = null!; +} \ No newline at end of file diff --git a/src/PacketLogger/ViewModels/Settings/SettingViewModelBase.cs b/src/PacketLogger/ViewModels/Settings/SettingViewModelBase.cs new file mode 100644 index 0000000..9caa999 --- /dev/null +++ b/src/PacketLogger/ViewModels/Settings/SettingViewModelBase.cs @@ -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; + +/// +/// A base viewmodel class for every settings tab. +/// +public abstract class SettingViewModelBase : ViewModelBase +{ + /// + /// Gets the name of the settings tab. + /// + public abstract string Name { get; } +} \ No newline at end of file diff --git a/src/PacketLogger/ViewModels/Settings/SettingsViewModel.cs b/src/PacketLogger/ViewModels/Settings/SettingsViewModel.cs new file mode 100644 index 0000000..f4bb3ae --- /dev/null +++ b/src/PacketLogger/ViewModels/Settings/SettingsViewModel.cs @@ -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; + +/// +public class SettingsViewModel : ViewModelBase +{ + private readonly FilterProfiles _filterProfiles; + + /// + /// Initializes a new instance of the class. + /// + /// The filter profiles. + public SettingsViewModel(FilterProfiles filterProfiles) + { + _filterProfiles = filterProfiles; + Settings = new[] + { + new FilterSettingsViewModel(filterProfiles) + }; + + SelectedSetting = Settings.First(); + } + + /// + /// Gets the setting tabs list. + /// + public IReadOnlyList Settings { get; } + + /// + /// Gets the currently selected tab. + /// + public SettingViewModelBase SelectedSetting { get; } +} \ No newline at end of file diff --git a/src/PacketLogger/Views/Filters/FilterChooseView.axaml b/src/PacketLogger/Views/Filters/FilterChooseView.axaml new file mode 100644 index 0000000..0ba066a --- /dev/null +++ b/src/PacketLogger/Views/Filters/FilterChooseView.axaml @@ -0,0 +1,25 @@ + + + + + + + + Recv + Send + + + + + + + + + diff --git a/src/PacketLogger/Views/Filters/FilterChooseView.axaml.cs b/src/PacketLogger/Views/Filters/FilterChooseView.axaml.cs new file mode 100644 index 0000000..10c6416 --- /dev/null +++ b/src/PacketLogger/Views/Filters/FilterChooseView.axaml.cs @@ -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 +{ + /// + /// Initializes a new instance of the class. + /// + public FilterChooseView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/PacketLogger/Views/Filters/FilterConfigView.axaml b/src/PacketLogger/Views/Filters/FilterConfigView.axaml new file mode 100644 index 0000000..0612ff1 --- /dev/null +++ b/src/PacketLogger/Views/Filters/FilterConfigView.axaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/PacketLogger/Views/Filters/FilterConfigView.axaml.cs b/src/PacketLogger/Views/Filters/FilterConfigView.axaml.cs new file mode 100644 index 0000000..def4d15 --- /dev/null +++ b/src/PacketLogger/Views/Filters/FilterConfigView.axaml.cs @@ -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 +{ + /// + /// Initializes a new instance of the class. + /// + public FilterConfigView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/PacketLogger/Views/PacketLogFilterView.axaml b/src/PacketLogger/Views/Filters/FilterEntryView.axaml similarity index 84% rename from src/PacketLogger/Views/PacketLogFilterView.axaml rename to src/PacketLogger/Views/Filters/FilterEntryView.axaml index 40f93d9..64a84df 100644 --- a/src/PacketLogger/Views/PacketLogFilterView.axaml +++ b/src/PacketLogger/Views/Filters/FilterEntryView.axaml @@ -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"> - + - @@ -24,11 +24,11 @@ - + - + - \ No newline at end of file + diff --git a/src/PacketLogger/Views/PacketLogFilterView.axaml.cs b/src/PacketLogger/Views/Filters/FilterEntryView.axaml.cs similarity index 72% rename from src/PacketLogger/Views/PacketLogFilterView.axaml.cs rename to src/PacketLogger/Views/Filters/FilterEntryView.axaml.cs index e4cbcd7..d316760 100644 --- a/src/PacketLogger/Views/PacketLogFilterView.axaml.cs +++ b/src/PacketLogger/Views/Filters/FilterEntryView.axaml.cs @@ -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 { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public PacketLogFilterView() + public FilterEntryView() { InitializeComponent(); this.FindControl("FilterType").Items = Enum.GetValues(); diff --git a/src/PacketLogger/Views/MainWindow.axaml b/src/PacketLogger/Views/MainWindow.axaml index 50ab453..868efa0 100644 --- a/src/PacketLogger/Views/MainWindow.axaml +++ b/src/PacketLogger/Views/MainWindow.axaml @@ -40,6 +40,7 @@ + diff --git a/src/PacketLogger/Views/PacketLogView.axaml b/src/PacketLogger/Views/PacketLogView.axaml deleted file mode 100644 index 9bb3d67..0000000 --- a/src/PacketLogger/Views/PacketLogView.axaml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - Recv - Send - - - - - - - - - - - - - -