M src/PacketLogger/App.axaml => src/PacketLogger/App.axaml +2 -1
@@ 8,6 8,7 @@
<Application.Styles>
<FluentTheme Mode="Dark" />
- <StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
+ <StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml" />
+ <StyleInclude Source="avares://Dock.Avalonia/Themes/DockFluentTheme.axaml" />
</Application.Styles>
</Application>=
\ No newline at end of file
A src/PacketLogger/Models/Packets/DummyPacketProvider.cs => src/PacketLogger/Models/Packets/DummyPacketProvider.cs +79 -0
@@ 0,0 1,79 @@
+//
+// DummyPacketProvider.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.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Reactive.Linq;
+using System.Threading.Tasks;
+using DynamicData;
+using DynamicData.Binding;
+using NosSmooth.PacketSerializer.Abstractions.Attributes;
+using PacketLogger.Models.Filters;
+using ReactiveUI;
+using Remora.Results;
+
+namespace PacketLogger.Models.Packets;
+
+/// <inheritdoc />
+public class DummyPacketProvider : IPacketProvider, IDisposable
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DummyPacketProvider"/> class.
+ /// </summary>
+ public DummyPacketProvider()
+ {
+ var index = 0;
+ Packets = new SourceList<PacketInfo>();
+ Packets.Add(new PacketInfo(index++, DateTime.Now, PacketSource.Client, "#cl"));
+ Packets.Add(new PacketInfo(index++, DateTime.Now, PacketSource.Client, "cl"));
+ for (var i = 0; i < 1000; i++)
+ {
+ Packets.Add
+ (new PacketInfo(index++, DateTime.Now.AddSeconds(-1000 + i), PacketSource.Client, "walk 10 10"));
+ Packets.Add
+ (new PacketInfo(index++, DateTime.Now.AddSeconds(-1000 + i), PacketSource.Server, "mv 1 50 52 123 123 89012390812 189023 182309 1823 189023 901283 091823 091823 901823 901283 091283 019283901283 901283 901 2831290 812390128390128213908139012839012839012390128390128938120938 1290 3190 adsadf"));
+ Packets.Add
+ (new PacketInfo(index++, DateTime.Now.AddSeconds(-1000 + i), PacketSource.Client, "walk 12 14"));
+ Packets.Add
+ (new PacketInfo(index++, DateTime.Now.AddSeconds(-1000 + i), PacketSource.Server, "mv 1 48 43"));
+ }
+ }
+
+ /// <inheritdoc />
+ public event PropertyChangedEventHandler? PropertyChanged;
+
+ /// <inheritdoc />
+ public bool IsOpen => false;
+
+ /// <inheritdoc />
+ public SourceList<PacketInfo> Packets { get; }
+
+ /// <inheritdoc />
+ public Task<Result> Open()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ /// <inheritdoc />
+ public Task<Result> Close()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ /// <inheritdoc />
+ public void Clear()
+ {
+ Packets.Clear();
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Packets.Dispose();
+ }
+}<
\ No newline at end of file
A src/PacketLogger/ViewModels/DockFactory.cs => src/PacketLogger/ViewModels/DockFactory.cs +115 -0
@@ 0,0 1,115 @@
+//
+// DockFactory.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 Dock.Avalonia.Controls;
+using Dock.Model.Controls;
+using Dock.Model.Core;
+using Dock.Model.Mvvm;
+using Dock.Model.Mvvm.Controls;
+using PacketLogger.Models;
+using ReactiveUI;
+
+namespace PacketLogger.ViewModels;
+
+/// <summary>
+/// A factory for root dock.
+/// </summary>
+public class DockFactory : Factory, IDisposable
+{
+ private NostaleProcesses _processes = new();
+
+ /// <inheritdoc />
+ public override IDocumentDock CreateDocumentDock()
+ {
+ var documentDock = new DocumentDock();
+ documentDock.CreateDocument = ReactiveCommand.Create
+ (
+ () =>
+ {
+ if (!documentDock.CanCreateDocument)
+ {
+ return;
+ }
+
+ var index = documentDock.VisibleDockables?.Count + 1;
+ var document = new PacketLogDocumentViewModel(_processes)
+ { Id = $"New tab {index}", Title = $"New tab {index}" };
+
+ AddDockable(documentDock, document);
+ SetActiveDockable(document);
+ SetFocusedDockable(documentDock, document);
+ }
+ );
+ return documentDock;
+ }
+
+ private readonly object _context;
+ private IRootDock? _rootDock;
+ private IDocumentDock? _documentDock;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DockFactory"/> class.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ public DockFactory(object context)
+ {
+ _context = context;
+ }
+
+ /// <inheritdoc />
+ public override IRootDock CreateLayout()
+ {
+ var initialTab = new PacketLogDocumentViewModel(_processes)
+ { Id = $"New tab", Title = $"New tab" };
+ var documentDock = CreateDocumentDock();
+ documentDock.IsCollapsable = false;
+ documentDock.ActiveDockable = initialTab;
+ documentDock.VisibleDockables = CreateList<IDockable>(initialTab);
+ documentDock.CanCreateDocument = true;
+
+ var rootDock = CreateRootDock();
+
+ rootDock.IsCollapsable = false;
+ rootDock.ActiveDockable = documentDock;
+ rootDock.DefaultDockable = documentDock;
+ rootDock.VisibleDockables = CreateList<IDockable>(documentDock);
+
+ _documentDock = documentDock;
+ _rootDock = rootDock;
+
+ return rootDock;
+ }
+
+ /// <inheritdoc />
+ public override void InitLayout(IDockable layout)
+ {
+ ContextLocator = new Dictionary<string, Func<object>>
+ {
+ ["Home"] = () => layout
+ };
+
+ DockableLocator = new Dictionary<string, Func<IDockable?>>
+ {
+ ["Root"] = () => _rootDock,
+ ["Documents"] = () => _documentDock
+ };
+
+ HostWindowLocator = new Dictionary<string, Func<IHostWindow>>
+ {
+ [nameof(IDockWindow)] = () => new HostWindow()
+ };
+
+ base.InitLayout(layout);
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ _processes.Dispose();
+ }
+}<
\ No newline at end of file
A src/PacketLogger/ViewModels/MainWindowViewModel.cs => src/PacketLogger/ViewModels/MainWindowViewModel.cs +43 -0
@@ 0,0 1,43 @@
+//
+// MainWindowViewModel.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 Dock.Model.Controls;
+using Dock.Model.Core;
+using PacketLogger.Models;
+using PacketLogger.Models.Packets;
+
+namespace PacketLogger.ViewModels;
+
+/// <inheritdoc />
+public class MainWindowViewModel : ViewModelBase, INotifyPropertyChanged
+{
+ private readonly IFactory? _factory;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MainWindowViewModel"/> class.
+ /// </summary>
+ public MainWindowViewModel()
+ {
+ _factory = new DockFactory(this);
+
+ Layout = _factory?.CreateLayout();
+ if (Layout is { })
+ {
+ _factory?.InitLayout(Layout);
+ if (Layout is { } root)
+ {
+ root.Navigate.Execute("Home");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the layout.
+ /// </summary>
+ public IRootDock? Layout { get; set; }
+}
A src/PacketLogger/Views/MainWindow.axaml => src/PacketLogger/Views/MainWindow.axaml +52 -0
@@ 0,0 1,52 @@
+<Window xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:vm="using:PacketLogger.ViewModels"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="300"
+ x:Class="PacketLogger.Views.MainWindow"
+ xmlns:np="https://np.com/visuals"
+ xmlns:views="clr-namespace:PacketLogger.Views"
+ xmlns:core="clr-namespace:Dock.Model.Core;assembly=Dock.Model"
+ ExtendClientAreaToDecorationsHint="True"
+ Title="PacketLogger"
+ FontFamily="avares://Avalonia.Themes.Fluent/Assets#Inter"
+ TransparencyLevelHint="AcrylicBlur">
+ <Design.DataContext>
+ <!-- This only sets the DataContext for the previewer in an IDE,
+ to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
+ <vm:MainWindowViewModel />
+ </Design.DataContext>
+
+ <DockPanel>
+ <Panel IsHitTestVisible="False" DockPanel.Dock="Top">
+ <Menu>
+ <MenuItem Header="_File">
+ <MenuItem Header="_Open File..." />
+ <Separator />
+ <MenuItem Header="_Save Filtered As..." />
+ <MenuItem Header="Save All As..." />
+ <Separator />
+ <MenuItem Header="Exit" />
+ </MenuItem>
+ <MenuItem Header="_Tools">
+ <MenuItem Header="_Packet Sender">
+ <MenuItem Header="_Test" />
+ </MenuItem>
+ <MenuItem Header="_Packet Analyzer"></MenuItem>
+ </MenuItem>
+ </Menu>
+ </Panel>
+
+ <Grid RowDefinitions="*, 25">
+ <DockControl Grid.Row="0" Grid.Column="0" x:Name="DockControl" Layout="{Binding Layout}" Margin="4" />
+ <Panel DataContext="{Binding Layout.ActiveDockable}"
+ Grid.Row="1" Grid.Column="0">
+ <TextBlock Text="{Binding FocusedDockable, FallbackValue={}}"
+ Margin="4"
+ x:DataType="core:IDock"
+ x:CompileBindings="True" />
+ </Panel>
+ </Grid>
+ </DockPanel>
+</Window><
\ No newline at end of file
A src/PacketLogger/Views/MainWindow.axaml.cs => src/PacketLogger/Views/MainWindow.axaml.cs +22 -0
@@ 0,0 1,22 @@
+//
+// MainWindow.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 PropertyChanged;
+
+namespace PacketLogger.Views;
+
+[DoNotNotify]
+public partial class MainWindow : Window
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MainWindow"/> class.
+ /// </summary>
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}<
\ No newline at end of file