mirror of
https://github.com/BlossomiShymae/Needlework.Net.git
synced 2025-12-06 10:10:48 +01:00
Add tabs view to endpoints
This commit is contained in:
@@ -55,6 +55,9 @@
|
||||
<Compile Update="Views\MainWindow\MainWindowView.axaml.cs">
|
||||
<DependentUpon>MainWindowView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Views\Pages\Endpoints\EndpointsNavigationView.axaml.cs">
|
||||
<DependentUpon>EndpointsNavigationView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Views\Pages\Endpoints\EndpointView.axaml.cs">
|
||||
<DependentUpon>EndpointView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
|
||||
@@ -19,6 +19,10 @@ namespace Needlework.Net
|
||||
{
|
||||
return new TextBlock { Text = "Data is null or has no name." };
|
||||
}
|
||||
if (!name.Contains("ViewModel"))
|
||||
{
|
||||
return new TextBlock { Text = "Data name must end with ViewModel." };
|
||||
}
|
||||
|
||||
name = name.Replace("ViewModel", "View");
|
||||
var type = Assembly.GetExecutingAssembly()
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Needlework.Net.ViewModels.Pages.Endpoints;
|
||||
|
||||
public partial class EndpointsContainerViewModel : PageBase
|
||||
{
|
||||
[ObservableProperty] private ObservableObject _activeViewModel;
|
||||
[ObservableProperty] private ObservableObject _endpointsViewModel;
|
||||
[ObservableProperty] private string _title = string.Empty;
|
||||
|
||||
public EndpointsContainerViewModel(HttpClient httpClient) : base("Endpoints", "list-alt", -500)
|
||||
{
|
||||
_activeViewModel = _endpointsViewModel = new EndpointsViewModel(httpClient, OnClicked);
|
||||
}
|
||||
|
||||
private void OnClicked(ObservableObject viewModel)
|
||||
{
|
||||
ActiveViewModel = viewModel;
|
||||
if (viewModel is EndpointViewModel endpoint) Title = endpoint.Title;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void GoBack()
|
||||
{
|
||||
ActiveViewModel = EndpointsViewModel;
|
||||
Title = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Avalonia.Collections;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System;
|
||||
|
||||
namespace Needlework.Net.ViewModels.Pages.Endpoints;
|
||||
|
||||
public partial class EndpointsNavigationViewModel : ObservableObject
|
||||
{
|
||||
public Guid Guid { get; } = Guid.NewGuid();
|
||||
|
||||
[ObservableProperty] private ObservableObject _activeViewModel;
|
||||
[ObservableProperty] private ObservableObject _endpointsViewModel;
|
||||
[ObservableProperty] private string _title = string.Empty;
|
||||
|
||||
private readonly Action<string?, Guid> _onEndpointNavigation;
|
||||
|
||||
public EndpointsNavigationViewModel(IAvaloniaList<string> plugins, Action<string?, Guid> onEndpointNavigation)
|
||||
{
|
||||
_activeViewModel = _endpointsViewModel = new EndpointsViewModel(plugins, OnClicked);
|
||||
_onEndpointNavigation = onEndpointNavigation;
|
||||
}
|
||||
|
||||
private void OnClicked(ObservableObject viewModel)
|
||||
{
|
||||
ActiveViewModel = viewModel;
|
||||
if (viewModel is EndpointViewModel endpoint)
|
||||
{
|
||||
Title = endpoint.Title;
|
||||
_onEndpointNavigation.Invoke(endpoint.Title, Guid);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void GoBack()
|
||||
{
|
||||
ActiveViewModel = EndpointsViewModel;
|
||||
Title = string.Empty;
|
||||
_onEndpointNavigation.Invoke(null, Guid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Needlework.Net.Messages;
|
||||
using System;
|
||||
|
||||
namespace Needlework.Net.ViewModels.Pages.Endpoints;
|
||||
|
||||
public partial class EndpointsTabViewModel : PageBase, IRecipient<DataReadyMessage>
|
||||
{
|
||||
public IAvaloniaList<string> Plugins { get; } = new AvaloniaList<string>();
|
||||
public IAvaloniaList<EndpointItem> Endpoints { get; } = new AvaloniaList<EndpointItem>();
|
||||
|
||||
[ObservableProperty] private bool _isBusy = true;
|
||||
|
||||
public EndpointsTabViewModel() : base("Endpoints", "list-alt", -500)
|
||||
{
|
||||
WeakReferenceMessenger.Default.RegisterAll(this);
|
||||
}
|
||||
|
||||
public void Receive(DataReadyMessage message)
|
||||
{
|
||||
IsBusy = false;
|
||||
Plugins.Clear();
|
||||
Plugins.AddRange(message.Value.Plugins.Keys);
|
||||
|
||||
Dispatcher.UIThread.Post(AddEndpoint);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void AddEndpoint()
|
||||
{
|
||||
Endpoints.Add(new()
|
||||
{
|
||||
Content = new EndpointsNavigationViewModel(Plugins, OnEndpointNavigation),
|
||||
Selected = true
|
||||
});
|
||||
}
|
||||
|
||||
private void OnEndpointNavigation(string? title, Guid guid)
|
||||
{
|
||||
foreach (var endpoint in Endpoints)
|
||||
{
|
||||
if (endpoint.Content.Guid.Equals(guid))
|
||||
{
|
||||
endpoint.Header = title ?? "Endpoints";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class EndpointItem : ObservableObject
|
||||
{
|
||||
[ObservableProperty] private string _header = "Endpoints";
|
||||
public IconSource IconSource { get; set; } = new SymbolIconSource() { Symbol = Symbol.Document, FontSize = 20.0, Foreground = Avalonia.Media.Brushes.White };
|
||||
public bool Selected { get; set; } = false;
|
||||
public required EndpointsNavigationViewModel Content { get; init; }
|
||||
}
|
||||
@@ -1,42 +1,26 @@
|
||||
using Avalonia.Collections;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Needlework.Net.Messages;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Needlework.Net.ViewModels.Pages.Endpoints;
|
||||
|
||||
public partial class EndpointsViewModel : ObservableObject, IRecipient<DataReadyMessage>
|
||||
public partial class EndpointsViewModel : ObservableObject
|
||||
{
|
||||
public HttpClient HttpClient { get; }
|
||||
public IAvaloniaList<string> Plugins { get; }
|
||||
public IAvaloniaList<string> Query { get; }
|
||||
|
||||
public string Title => "Endpoints";
|
||||
public Action<ObservableObject> OnClicked;
|
||||
public IAvaloniaList<string> Plugins { get; } = new AvaloniaList<string>();
|
||||
public IAvaloniaList<string> Query { get; } = new AvaloniaList<string>();
|
||||
|
||||
[ObservableProperty] private bool _isBusy = true;
|
||||
[ObservableProperty] private string _search = string.Empty;
|
||||
[ObservableProperty] private string? _selectedQuery = string.Empty;
|
||||
|
||||
public EndpointsViewModel(HttpClient httpClient, Action<ObservableObject> onClicked)
|
||||
public Action<ObservableObject> OnClicked { get; }
|
||||
|
||||
public EndpointsViewModel(IAvaloniaList<string> plugins, Action<ObservableObject> onClicked)
|
||||
{
|
||||
HttpClient = httpClient;
|
||||
Plugins = plugins;
|
||||
Query = plugins;
|
||||
OnClicked = onClicked;
|
||||
|
||||
WeakReferenceMessenger.Default.Register(this);
|
||||
}
|
||||
|
||||
public void Receive(DataReadyMessage message)
|
||||
{
|
||||
IsBusy = false;
|
||||
Plugins.Clear();
|
||||
Plugins.AddRange(message.Value.Plugins.Keys);
|
||||
Query.Clear();
|
||||
Query.AddRange(Plugins);
|
||||
}
|
||||
|
||||
partial void OnSearchChanged(string value)
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
xmlns:avalonEdit="https://github.com/avaloniaui/avaloniaedit"
|
||||
xmlns:i="https://github.com/projektanker/icons.avalonia"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Needlework.Net.Views.Pages.Endpoints.EndpointsContainerView"
|
||||
x:DataType="vm:EndpointsContainerViewModel">
|
||||
x:Class="Needlework.Net.Views.Pages.Endpoints.EndpointsNavigationView"
|
||||
x:DataType="vm:EndpointsNavigationViewModel">
|
||||
<Grid RowDefinitions="auto,*"
|
||||
ColumnDefinitions="*"
|
||||
Margin="16">
|
||||
@@ -2,9 +2,9 @@ using Avalonia.Controls;
|
||||
|
||||
namespace Needlework.Net.Views.Pages.Endpoints;
|
||||
|
||||
public partial class EndpointsContainerView : UserControl
|
||||
public partial class EndpointsNavigationView : UserControl
|
||||
{
|
||||
public EndpointsContainerView()
|
||||
public EndpointsNavigationView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
35
Needlework.Net/Views/Pages/Endpoints/EndpointsTabView.axaml
Normal file
35
Needlework.Net/Views/Pages/Endpoints/EndpointsTabView.axaml
Normal file
@@ -0,0 +1,35 @@
|
||||
<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:i="https://github.com/projektanker/icons.avalonia"
|
||||
xmlns:vm="using:Needlework.Net.ViewModels.Pages.Endpoints"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
xmlns:controls="using:Needlework.Net.Controls"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Needlework.Net.Views.Pages.Endpoints.EndpointsTabView"
|
||||
x:DataType="vm:EndpointsTabViewModel">
|
||||
<controls:BusyArea IsBusy="{Binding IsBusy}"
|
||||
BusyText="Loading...">
|
||||
<Grid>
|
||||
<ui:TabView TabItems="{Binding Endpoints}"
|
||||
AddTabButtonCommand="{Binding AddEndpointCommand}"
|
||||
TabCloseRequested="TabView_TabCloseRequested">
|
||||
<ui:TabView.TabItemTemplate>
|
||||
<DataTemplate DataType="vm:EndpointItem">
|
||||
<ui:TabViewItem Header="{Binding Header}"
|
||||
IconSource="{Binding IconSource}"
|
||||
IsSelected="{Binding Selected}"
|
||||
Content="{Binding}">
|
||||
<ui:TabViewItem.ContentTemplate>
|
||||
<DataTemplate DataType="vm:EndpointItem">
|
||||
<ContentControl Content="{Binding Content}"/>
|
||||
</DataTemplate>
|
||||
</ui:TabViewItem.ContentTemplate>
|
||||
</ui:TabViewItem>
|
||||
</DataTemplate>
|
||||
</ui:TabView.TabItemTemplate>
|
||||
</ui:TabView>
|
||||
</Grid>
|
||||
</controls:BusyArea>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,19 @@
|
||||
using Avalonia.Controls;
|
||||
using Needlework.Net.ViewModels.Pages.Endpoints;
|
||||
using System.Collections;
|
||||
|
||||
namespace Needlework.Net.Views.Pages.Endpoints;
|
||||
|
||||
public partial class EndpointsTabView : UserControl
|
||||
{
|
||||
public EndpointsTabView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void TabView_TabCloseRequested(FluentAvalonia.UI.Controls.TabView sender, FluentAvalonia.UI.Controls.TabViewTabCloseRequestedEventArgs args)
|
||||
{
|
||||
if (args.Tab.Content is EndpointItem item)
|
||||
((IList)sender.TabItems).Remove(item);
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@
|
||||
Name="EndpointsControl"
|
||||
x:Class="Needlework.Net.Views.Pages.Endpoints.EndpointsView"
|
||||
x:DataType="vm:EndpointsViewModel">
|
||||
<controls:BusyArea IsBusy="{Binding IsBusy}"
|
||||
BusyText="Loading...">
|
||||
<Grid RowDefinitions="auto,auto,*" ColumnDefinitions="*">
|
||||
<TextBox Watermark="Search" Margin="0 4" Text="{Binding Search}" Grid.Row="1" Grid.Column="0"/>
|
||||
<ScrollViewer Grid.Row="2" Grid.Column="0">
|
||||
@@ -28,5 +26,4 @@
|
||||
</ItemsRepeater>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</controls:BusyArea>
|
||||
</UserControl>
|
||||
Reference in New Issue
Block a user