~ruther/NosTale-PacketLogger

8d8f5e755525916412186587ee04129a1052f001 — Rutherther 2 years ago 1c64e3b
feat: add main window docking
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

Do not follow this link