mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Added basic profile list
This commit is contained in:
parent
65f81ab768
commit
428bbd73e3
@ -2,7 +2,20 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:categories="clr-namespace:Artemis.UI.Screens.Workshop.Categories"
|
||||||
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Workshop.Categories.CategoriesView">
|
x:Class="Artemis.UI.Screens.Workshop.Categories.CategoriesView"
|
||||||
Welcome to Avalonia!
|
x:DataType="categories:CategoriesViewModel">
|
||||||
|
<ItemsRepeater ItemsSource="{CompiledBinding Categories}">
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate DataType="categories:CategoryViewModel">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="5" Background="Transparent" Cursor="Hand" PointerReleased="InputElement_OnPointerReleased">
|
||||||
|
<CheckBox IsChecked="{CompiledBinding IsSelected}" Padding="1 5 1 0"/>
|
||||||
|
<avalonia:MaterialIcon Kind="{CompiledBinding Icon}" />
|
||||||
|
<TextBlock Text="{CompiledBinding Name}" VerticalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Input;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
@ -16,4 +16,10 @@ public partial class CategoriesView : ReactiveUserControl<CategoriesViewModel>
|
|||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.InitialPressMouseButton == MouseButton.Left && sender is IDataContextProvider p && p.DataContext is CategoryViewModel categoryViewModel)
|
||||||
|
categoryViewModel.IsSelected = !categoryViewModel.IsSelected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,14 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
|
using ReactiveUI;
|
||||||
|
using Serilog;
|
||||||
|
using StrawberryShake;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.Categories;
|
namespace Artemis.UI.Screens.Workshop.Categories;
|
||||||
|
|
||||||
public class CategoriesViewModel : ActivatableViewModelBase
|
public class CategoriesViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IWorkshopClient _client;
|
private readonly IWorkshopClient _client;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private IReadOnlyList<CategoryViewModel> _categories;
|
||||||
|
|
||||||
public CategoriesViewModel(IWorkshopClient client)
|
public CategoriesViewModel(ILogger logger, IWorkshopClient client)
|
||||||
{
|
{
|
||||||
|
_logger = logger;
|
||||||
_client = client;
|
_client = client;
|
||||||
|
|
||||||
|
this.WhenActivated(d => ReactiveCommand.CreateFromTask(GetCategories).Execute().Subscribe().DisposeWith(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<CategoryViewModel> Categories
|
||||||
|
{
|
||||||
|
get => _categories;
|
||||||
|
set => RaiseAndSetIfChanged(ref _categories, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetCategories(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IOperationResult<IGetCategoriesResult> result = await _client.GetCategories.ExecuteAsync(cancellationToken);
|
||||||
|
if (result.IsErrorResult())
|
||||||
|
_logger.Warning("Failed to retrieve categories {Error}", result.Errors);
|
||||||
|
|
||||||
|
Categories = result.Data?.Categories.Select(c => new CategoryViewModel(c)).ToList() ?? new List<CategoryViewModel>();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Warning(e, "Failed to retrieve categories");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
using Material.Icons;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Categories;
|
||||||
|
|
||||||
|
public class CategoryViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
private bool _isSelected;
|
||||||
|
|
||||||
|
public CategoryViewModel(IGetCategories_Categories category)
|
||||||
|
{
|
||||||
|
Id = category.Id;
|
||||||
|
Name = category.Name;
|
||||||
|
if (Enum.TryParse(typeof(MaterialIconKind), category.Icon, out object? icon))
|
||||||
|
Icon = icon as MaterialIconKind? ?? MaterialIconKind.QuestionMarkCircle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Id { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public MaterialIconKind Icon { get; }
|
||||||
|
|
||||||
|
public bool IsSelected
|
||||||
|
{
|
||||||
|
get => _isSelected;
|
||||||
|
set => RaiseAndSetIfChanged(ref _isSelected, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,10 @@
|
|||||||
<Border Classes="router-container">
|
<Border Classes="router-container">
|
||||||
<Grid ColumnDefinitions="300,*" Margin="10">
|
<Grid ColumnDefinitions="300,*" Margin="10">
|
||||||
<Border Classes="card-condensed" Grid.Column="0" Margin="0 0 10 0">
|
<Border Classes="card-condensed" Grid.Column="0" Margin="0 0 10 0">
|
||||||
<TextBlock>Side panel</TextBlock>
|
<StackPanel>
|
||||||
|
<TextBlock Classes="h3">Categories</TextBlock>
|
||||||
|
<ContentControl Content="{CompiledBinding CategoriesViewModel}"></ContentControl>
|
||||||
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Classes="card-condensed" Grid.Column="1">
|
<Border Classes="card-condensed" Grid.Column="1">
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.UI.Screens.Workshop.Categories;
|
||||||
using Artemis.UI.Screens.Workshop.Parameters;
|
using Artemis.UI.Screens.Workshop.Parameters;
|
||||||
using Artemis.UI.Screens.Workshop.Search;
|
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
@ -13,11 +13,13 @@ public class LayoutListViewModel : RoutableScreen<ActivatableViewModelBase, Work
|
|||||||
{
|
{
|
||||||
private int _page;
|
private int _page;
|
||||||
|
|
||||||
/// <inheritdoc />
|
public LayoutListViewModel(CategoriesViewModel categoriesViewModel)
|
||||||
public LayoutListViewModel()
|
|
||||||
{
|
{
|
||||||
|
CategoriesViewModel = categoriesViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CategoriesViewModel CategoriesViewModel { get; }
|
||||||
|
|
||||||
public int Page
|
public int Page
|
||||||
{
|
{
|
||||||
get => _page;
|
get => _page;
|
||||||
|
|||||||
@ -0,0 +1,39 @@
|
|||||||
|
<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:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
|
xmlns:profile="clr-namespace:Artemis.UI.Screens.Workshop.Profile"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="120"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.Profile.ProfileListEntryView"
|
||||||
|
x:DataType="profile:ProfileListEntryViewModel">
|
||||||
|
<Border Classes="card">
|
||||||
|
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||||
|
<avalonia:MaterialIcon Kind="Abacus" Width="80" Height="80" Margin="0 0 10 0" Grid.Column="0" VerticalAlignment="Center" />
|
||||||
|
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||||
|
<TextBlock Classes="h4 no-margin" Text="{CompiledBinding Entry.Name, FallbackValue=Title}"></TextBlock>
|
||||||
|
<TextBlock Classes="subtitle" Text="{CompiledBinding Entry.Summary, FallbackValue=Summary}"></TextBlock>
|
||||||
|
|
||||||
|
<ItemsControl ItemsSource="{CompiledBinding Entry.Categories}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8"></StackPanel>
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Margin="0 0 3 0"></avalonia:MaterialIcon>
|
||||||
|
<TextBlock Text="{CompiledBinding Name}"></TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="2">
|
||||||
|
<TextBlock>Downloads</TextBlock>
|
||||||
|
<TextBlock>Last updated</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Profile;
|
||||||
|
|
||||||
|
public partial class ProfileListEntryView : UserControl
|
||||||
|
{
|
||||||
|
public ProfileListEntryView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Profile;
|
||||||
|
|
||||||
|
public class ProfileListEntryViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
public ProfileListEntryViewModel(IGetEntries_Entries_Nodes entry)
|
||||||
|
{
|
||||||
|
Entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IGetEntries_Entries_Nodes Entry { get; }
|
||||||
|
}
|
||||||
@ -8,14 +8,22 @@
|
|||||||
x:DataType="profile:ProfileListViewModel">
|
x:DataType="profile:ProfileListViewModel">
|
||||||
<Border Classes="router-container">
|
<Border Classes="router-container">
|
||||||
<Grid ColumnDefinitions="300,*" Margin="10">
|
<Grid ColumnDefinitions="300,*" Margin="10">
|
||||||
<Border Classes="card-condensed" Grid.Column="0" Margin="0 0 10 0">
|
<Border Classes="card-condensed" Grid.Column="0" Margin="0 0 10 0" VerticalAlignment="Top">
|
||||||
<TextBlock>Side panel</TextBlock>
|
<StackPanel>
|
||||||
|
<TextBlock Classes="h3">Categories</TextBlock>
|
||||||
|
<ContentControl Content="{CompiledBinding CategoriesViewModel}"></ContentControl>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Classes="card-condensed" Grid.Column="1">
|
<Border Classes="card-condensed" Grid.Column="1">
|
||||||
<TextBlock>
|
<ItemsRepeater ItemsSource="{CompiledBinding Entries}">
|
||||||
<Run Text="Profile list main panel, page: " /><Run Text="{CompiledBinding Page}"></Run>
|
<ItemsRepeater.ItemTemplate>
|
||||||
</TextBlock>
|
<DataTemplate>
|
||||||
|
<ContentControl Content="{CompiledBinding}" Margin="0 0 0 5"></ContentControl>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@ -1,34 +1,70 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.UI.Screens.Workshop.Categories;
|
||||||
using Artemis.UI.Screens.Workshop.Parameters;
|
using Artemis.UI.Screens.Workshop.Parameters;
|
||||||
using Artemis.UI.Screens.Workshop.Search;
|
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
|
using DynamicData;
|
||||||
|
using ReactiveUI;
|
||||||
|
using StrawberryShake;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.Profile;
|
namespace Artemis.UI.Screens.Workshop.Profile;
|
||||||
|
|
||||||
public class ProfileListViewModel : RoutableScreen<ActivatableViewModelBase, WorkshopListParameters>, IWorkshopViewModel
|
public class ProfileListViewModel : RoutableScreen<ActivatableViewModelBase, WorkshopListParameters>, IWorkshopViewModel
|
||||||
{
|
{
|
||||||
|
private readonly SourceList<IGetEntries_Entries_Nodes> _entries;
|
||||||
|
private readonly IWorkshopClient _workshopClient;
|
||||||
private int _page;
|
private int _page;
|
||||||
|
|
||||||
/// <inheritdoc />
|
public ProfileListViewModel(IWorkshopClient workshopClient, CategoriesViewModel categoriesViewModel)
|
||||||
public ProfileListViewModel()
|
|
||||||
{
|
{
|
||||||
|
_workshopClient = workshopClient;
|
||||||
|
CategoriesViewModel = categoriesViewModel;
|
||||||
|
|
||||||
|
_entries = new SourceList<IGetEntries_Entries_Nodes>();
|
||||||
|
_entries.Connect()
|
||||||
|
.Transform(e => new ProfileListEntryViewModel(e))
|
||||||
|
.Bind(out ReadOnlyObservableCollection<ProfileListEntryViewModel> observableEntries)
|
||||||
|
.Subscribe();
|
||||||
|
Entries = observableEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CategoriesViewModel CategoriesViewModel { get; }
|
||||||
|
public ReadOnlyObservableCollection<ProfileListEntryViewModel> Entries { get; set; }
|
||||||
|
|
||||||
public int Page
|
public int Page
|
||||||
{
|
{
|
||||||
get => _page;
|
get => _page;
|
||||||
set => RaiseAndSetIfChanged(ref _page, value);
|
set => RaiseAndSetIfChanged(ref _page, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task OnNavigating(WorkshopListParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
public override async Task OnNavigating(WorkshopListParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Page = Math.Max(1, parameters.Page);
|
Page = Math.Max(1, parameters.Page);
|
||||||
return Task.CompletedTask;
|
await GetEntries(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetEntries(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
IOperationResult<IGetEntriesResult> result = await _workshopClient.GetEntries.ExecuteAsync(CreateFilter(), cancellationToken);
|
||||||
|
if (result.IsErrorResult() || result.Data?.Entries?.Nodes == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_entries.Edit(e =>
|
||||||
|
{
|
||||||
|
e.Clear();
|
||||||
|
e.AddRange(result.Data.Entries.Nodes);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntryFilterInput CreateFilter()
|
||||||
|
{
|
||||||
|
return new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = WebClient.Workshop.EntryType.Profile}};
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntryType? EntryType => null;
|
public EntryType? EntryType => null;
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
query GetEntries {
|
query GetEntries($filter: EntryFilterInput) {
|
||||||
entries {
|
entries(where: $filter) {
|
||||||
nodes {
|
nodes {
|
||||||
author
|
author
|
||||||
name
|
name
|
||||||
|
summary
|
||||||
entryType
|
entryType
|
||||||
|
categories {
|
||||||
|
name
|
||||||
|
icon
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user