mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Added workshop home, changed VM routing structure
This commit is contained in:
parent
99a365be0b
commit
65f81ab768
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Platform;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Routing;
|
namespace Artemis.UI.Shared.Routing;
|
||||||
|
|
||||||
@ -72,7 +73,15 @@ public abstract class RoutableScreen<TScreen, TParam> : ActivatableViewModelBase
|
|||||||
|
|
||||||
void IRoutableScreen.InternalChangeScreen(object? screen)
|
void IRoutableScreen.InternalChangeScreen(object? screen)
|
||||||
{
|
{
|
||||||
Screen = screen as TScreen;
|
if (screen == null)
|
||||||
|
{
|
||||||
|
Screen = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen is not TScreen typedScreen)
|
||||||
|
throw new ArtemisRoutingException($"Provided screen is not assignable to {typeof(TScreen).FullName}");
|
||||||
|
Screen = typedScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task IRoutableScreen.InternalOnNavigating(NavigationArguments args, CancellationToken cancellationToken)
|
async Task IRoutableScreen.InternalOnNavigating(NavigationArguments args, CancellationToken cancellationToken)
|
||||||
|
|||||||
@ -70,7 +70,17 @@ internal class Navigation
|
|||||||
|
|
||||||
// Only change the screen if it wasn't reused
|
// Only change the screen if it wasn't reused
|
||||||
if (!ReferenceEquals(host.InternalScreen, screen))
|
if (!ReferenceEquals(host.InternalScreen, screen))
|
||||||
host.InternalChangeScreen(screen);
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
host.InternalChangeScreen(screen);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Cancel();
|
||||||
|
_logger.Error(e, "Failed to navigate to {Path}", resolution.Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (CancelIfRequested(args, "ChangeScreen", screen))
|
if (CancelIfRequested(args, "ChangeScreen", screen))
|
||||||
return;
|
return;
|
||||||
@ -93,8 +103,16 @@ internal class Navigation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolution.Child != null && screen is IRoutableScreen childScreen)
|
if (screen is IRoutableScreen childScreen)
|
||||||
await NavigateResolution(resolution.Child, args, childScreen);
|
{
|
||||||
|
// Navigate the child too
|
||||||
|
if (resolution.Child != null)
|
||||||
|
await NavigateResolution(resolution.Child, args, childScreen);
|
||||||
|
// Make sure there is no child
|
||||||
|
else if (childScreen.InternalScreen != null)
|
||||||
|
childScreen.InternalChangeScreen(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Completed = true;
|
Completed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
src/Artemis.UI/Assets/Images/workshop-banner.jpg
Normal file
BIN
src/Artemis.UI/Assets/Images/workshop-banner.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
@ -15,7 +15,7 @@
|
|||||||
<windowing:AppWindow.Styles>
|
<windowing:AppWindow.Styles>
|
||||||
<Styles>
|
<Styles>
|
||||||
<Style Selector="Border#TitleBarContainer">
|
<Style Selector="Border#TitleBarContainer">
|
||||||
<Setter Property="Height" Value="40"></Setter>
|
<Setter Property="MinHeight" Value="40"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="windowing|AppWindow:windows Border#TitleBarContainer">
|
<Style Selector="windowing|AppWindow:windows Border#TitleBarContainer">
|
||||||
<Setter Property="Margin" Value="0 0 138 0"></Setter>
|
<Setter Property="Margin" Value="0 0 138 0"></Setter>
|
||||||
|
|||||||
@ -16,15 +16,17 @@ public static class Routes
|
|||||||
public static List<IRouterRegistration> ArtemisRoutes = new()
|
public static List<IRouterRegistration> ArtemisRoutes = new()
|
||||||
{
|
{
|
||||||
new RouteRegistration<HomeViewModel>("home"),
|
new RouteRegistration<HomeViewModel>("home"),
|
||||||
|
new RouteRegistration<WorkshopViewModel>("workshop")
|
||||||
new RouteRegistration<WorkshopViewModel>("workshop"),
|
{
|
||||||
new RouteRegistration<ProfileListViewModel>("workshop/profiles/{page:int}"),
|
Children = new List<IRouterRegistration>()
|
||||||
new RouteRegistration<ProfileDetailsViewModel>("workshop/profiles/{entryId:guid}"),
|
{
|
||||||
new RouteRegistration<LayoutListViewModel>("workshop/layouts/{page:int}"),
|
new RouteRegistration<ProfileListViewModel>("profiles/{page:int}"),
|
||||||
new RouteRegistration<LayoutDetailsViewModel>("workshop/layouts/{entryId:guid}"),
|
new RouteRegistration<ProfileDetailsViewModel>("profiles/{entryId:guid}"),
|
||||||
|
new RouteRegistration<LayoutListViewModel>("layouts/{page:int}"),
|
||||||
|
new RouteRegistration<LayoutDetailsViewModel>("layouts/{entryId:guid}")
|
||||||
|
}
|
||||||
|
},
|
||||||
new RouteRegistration<SurfaceEditorViewModel>("surface-editor"),
|
new RouteRegistration<SurfaceEditorViewModel>("surface-editor"),
|
||||||
|
|
||||||
new RouteRegistration<SettingsViewModel>("settings")
|
new RouteRegistration<SettingsViewModel>("settings")
|
||||||
{
|
{
|
||||||
Children = new List<IRouterRegistration>
|
Children = new List<IRouterRegistration>
|
||||||
|
|||||||
@ -15,20 +15,17 @@
|
|||||||
Height="200"
|
Height="200"
|
||||||
Stretch="UniformToFill"
|
Stretch="UniformToFill"
|
||||||
RenderOptions.BitmapInterpolationMode="HighQuality"/>
|
RenderOptions.BitmapInterpolationMode="HighQuality"/>
|
||||||
|
|
||||||
<!-- TODO: Replace with a shadow when available -->
|
|
||||||
<TextBlock Grid.Row="0"
|
<TextBlock Grid.Row="0"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
Foreground="Black"
|
Foreground="White"
|
||||||
FontSize="32"
|
FontSize="32"
|
||||||
Margin="32"
|
Margin="30"
|
||||||
Text=" Welcome to Artemis, the unified RGB platform." />
|
Text=" Welcome to Artemis, the unified RGB platform.">
|
||||||
<TextBlock Grid.Row="0"
|
<TextBlock.Effect>
|
||||||
TextWrapping="Wrap"
|
<DropShadowEffect Color="Black" OffsetX="2" OffsetY="2" BlurRadius="5"></DropShadowEffect>
|
||||||
Foreground="White"
|
</TextBlock.Effect>
|
||||||
FontSize="32"
|
</TextBlock>
|
||||||
Margin="30"
|
|
||||||
Text=" Welcome to Artemis, the unified RGB platform." />
|
|
||||||
|
|
||||||
<Grid Grid.Row="1" MaxWidth="840" Margin="30" VerticalAlignment="Bottom" ColumnDefinitions="*,*" RowDefinitions="*,*">
|
<Grid Grid.Row="1" MaxWidth="840" Margin="30" VerticalAlignment="Bottom" ColumnDefinitions="*,*" RowDefinitions="*,*">
|
||||||
<Border Classes="card" Margin="8" Grid.ColumnSpan="2" ClipToBounds="True">
|
<Border Classes="card" Margin="8" Grid.ColumnSpan="2" ClipToBounds="True">
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Sidebar.SidebarScreenView"
|
x:Class="Artemis.UI.Screens.Sidebar.SidebarScreenView"
|
||||||
x:DataType="vm:SidebarScreenViewModel">
|
x:DataType="vm:SidebarScreenViewModel">
|
||||||
<StackPanel Orientation="Horizontal" Background="Transparent" PointerReleased="InputElement_OnPointerReleased" DoubleTapped="InputElement_OnDoubleTapped">
|
<StackPanel Orientation="Horizontal" Height="34" Background="Transparent" PointerPressed="InputElement_OnPointerPressed" DoubleTapped="InputElement_OnDoubleTapped" >
|
||||||
<avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Width="18" Height="18" />
|
<avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Width="18" Height="18" />
|
||||||
<TextBlock Margin="10 0" VerticalAlignment="Center" FontSize="13" Text="{CompiledBinding DisplayName}" />
|
<TextBlock Margin="10 0" VerticalAlignment="Center" FontSize="13" Text="{CompiledBinding DisplayName}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Sidebar;
|
namespace Artemis.UI.Screens.Sidebar;
|
||||||
@ -14,12 +12,18 @@ public partial class SidebarScreenView : ReactiveUserControl<SidebarScreenViewMo
|
|||||||
|
|
||||||
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
// if (ViewModel != null)
|
if (ViewModel != null)
|
||||||
// ViewModel.IsExpanded = !ViewModel.IsExpanded;
|
ViewModel.IsExpanded = !ViewModel.IsExpanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InputElement_OnDoubleTapped(object? sender, TappedEventArgs e)
|
private void InputElement_OnDoubleTapped(object? sender, TappedEventArgs e)
|
||||||
{
|
{
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InputElement_OnPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
if (ViewModel != null)
|
||||||
|
ViewModel.IsExpanded = !ViewModel.IsExpanded;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -2,11 +2,7 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Routing;
|
|
||||||
using Artemis.UI.Shared.Services;
|
|
||||||
using Avalonia.Threading;
|
|
||||||
using Material.Icons;
|
using Material.Icons;
|
||||||
using ReactiveUI;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Sidebar;
|
namespace Artemis.UI.Screens.Sidebar;
|
||||||
|
|
||||||
@ -22,7 +18,7 @@ public class SidebarScreenViewModel : ViewModelBase
|
|||||||
DisplayName = displayName;
|
DisplayName = displayName;
|
||||||
Screens = screens ?? new ObservableCollection<SidebarScreenViewModel>();
|
Screens = screens ?? new ObservableCollection<SidebarScreenViewModel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MaterialIconKind Icon { get; }
|
public MaterialIconKind Icon { get; }
|
||||||
public string Path { get; }
|
public string Path { get; }
|
||||||
public string RootPath { get; }
|
public string RootPath { get; }
|
||||||
@ -56,15 +52,12 @@ public class SidebarScreenViewModel : ViewModelBase
|
|||||||
|
|
||||||
public void ExpandIfRequired(SidebarScreenViewModel selected)
|
public void ExpandIfRequired(SidebarScreenViewModel selected)
|
||||||
{
|
{
|
||||||
if (selected == this && Screens.Any())
|
if (selected == this)
|
||||||
{
|
|
||||||
IsExpanded = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (Screens.Contains(selected))
|
if (Screens.Contains(selected))
|
||||||
IsExpanded = true;
|
IsExpanded = true;
|
||||||
|
|
||||||
foreach (SidebarScreenViewModel sidebarScreenViewModel in Screens)
|
foreach (SidebarScreenViewModel sidebarScreenViewModel in Screens)
|
||||||
sidebarScreenViewModel.ExpandIfRequired(selected);
|
sidebarScreenViewModel.ExpandIfRequired(selected);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
<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"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.Categories.CategoriesView">
|
||||||
|
Welcome to Avalonia!
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Categories;
|
||||||
|
|
||||||
|
public partial class CategoriesView : ReactiveUserControl<CategoriesViewModel>
|
||||||
|
{
|
||||||
|
public CategoriesView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Categories;
|
||||||
|
|
||||||
|
public class CategoriesViewModel : ActivatableViewModelBase
|
||||||
|
{
|
||||||
|
private readonly IWorkshopClient _client;
|
||||||
|
|
||||||
|
public CategoriesViewModel(IWorkshopClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml
Normal file
58
src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<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:home="clr-namespace:Artemis.UI.Screens.Workshop.Home"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.Home.WorkshopHomeView"
|
||||||
|
x:DataType="home:WorkshopHomeViewModel">
|
||||||
|
<Border Classes="router-container">
|
||||||
|
<Grid RowDefinitions="200,*">
|
||||||
|
<Image Grid.Row="0"
|
||||||
|
Grid.RowSpan="2"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Source="/Assets/Images/workshop-banner.jpg"
|
||||||
|
Height="200"
|
||||||
|
Stretch="UniformToFill"
|
||||||
|
RenderOptions.BitmapInterpolationMode="HighQuality">
|
||||||
|
<Image.OpacityMask>
|
||||||
|
<LinearGradientBrush StartPoint="0%,70%" EndPoint="0%,100%">
|
||||||
|
<GradientStops>
|
||||||
|
<GradientStop Color="Black" Offset="0"></GradientStop>
|
||||||
|
<GradientStop Color="Transparent" Offset="100"></GradientStop>
|
||||||
|
</GradientStops>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
</Image.OpacityMask>
|
||||||
|
</Image>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="White"
|
||||||
|
FontSize="32"
|
||||||
|
Margin="30"
|
||||||
|
Text="Welcome to the Artemis Workshop!">
|
||||||
|
<TextBlock.Effect>
|
||||||
|
<DropShadowEffect Color="Black" OffsetX="2" OffsetY="2" BlurRadius="5"></DropShadowEffect>
|
||||||
|
</TextBlock.Effect>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="1" Margin="30 -75 30 0" Spacing="10" Orientation="Horizontal" VerticalAlignment="Top">
|
||||||
|
<Button Width="150" Height="180" Command="{CompiledBinding Navigate}" CommandParameter="workshop/profiles/1" VerticalContentAlignment="Top">
|
||||||
|
<StackPanel>
|
||||||
|
<avalonia:MaterialIcon Kind="FolderVideo" HorizontalAlignment="Left" Width="60" Height="60" Margin="0 5"/>
|
||||||
|
<TextBlock TextWrapping="Wrap" FontSize="16" Margin="0 5">Profiles</TextBlock>
|
||||||
|
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.8">Browse new profiles created by other users.</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Width="150" Height="180" Command="{CompiledBinding Navigate}" CommandParameter="workshop/layouts/1" VerticalContentAlignment="Top">
|
||||||
|
<StackPanel>
|
||||||
|
<avalonia:MaterialIcon Kind="KeyboardVariant" HorizontalAlignment="Left" Width="60" Height="60" Margin="0 5"/>
|
||||||
|
<TextBlock TextWrapping="Wrap" FontSize="16" Margin="0 5">Layouts</TextBlock>
|
||||||
|
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.8">Layouts make your devices look great in the editor.</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Home;
|
||||||
|
|
||||||
|
public partial class WorkshopHomeView : ReactiveUserControl<WorkshopHomeViewModel>
|
||||||
|
{
|
||||||
|
public WorkshopHomeView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
using System.Reactive;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Routing;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Home;
|
||||||
|
|
||||||
|
public class WorkshopHomeViewModel : ActivatableViewModelBase, IWorkshopViewModel
|
||||||
|
{
|
||||||
|
public WorkshopHomeViewModel(IRouter router)
|
||||||
|
{
|
||||||
|
Navigate = ReactiveCommand.CreateFromTask<string>(async r => await router.Navigate(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReactiveCommand<string, Unit> Navigate { get; set; }
|
||||||
|
|
||||||
|
public EntryType? EntryType => null;
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,20 +2,24 @@
|
|||||||
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:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:layout="clr-namespace:Artemis.UI.Screens.Workshop.Layout"
|
||||||
xmlns:ui="clr-namespace:Artemis.UI"
|
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Workshop.Layout.LayoutDetailsView">
|
x:Class="Artemis.UI.Screens.Workshop.Layout.LayoutDetailsView"
|
||||||
|
x:DataType="layout:LayoutDetailsViewModel">
|
||||||
<Border Classes="router-container">
|
<Border Classes="router-container">
|
||||||
<Grid ColumnDefinitions="300,*" Margin="10">
|
<Grid ColumnDefinitions="300,*" RowDefinitions="Auto,*" Margin="10">
|
||||||
<Border Classes="card-condensed" Grid.Column="0" Margin="0 0 10 0">
|
<StackPanel Grid.Row="0" Grid.ColumnSpan="2" >
|
||||||
|
<TextBlock Text="{CompiledBinding Entry.Name, FallbackValue=Layout}" Classes="h3 no-margin"/>
|
||||||
|
<TextBlock Text="{CompiledBinding Entry.Author, FallbackValue=Author}" Classes="subtitle" Margin="0 0 0 5"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Border Classes="card-condensed" Grid.Row="1" Grid.Column="0" Margin="0 0 10 0">
|
||||||
<TextBlock>Side panel</TextBlock>
|
<TextBlock>Side panel</TextBlock>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Classes="card-condensed" Grid.Column="1">
|
<Border Classes="card-condensed" Grid.Row="1" Grid.Column="1">
|
||||||
<TextBlock>Main panel</TextBlock>
|
<TextBlock>Layout details panel</TextBlock>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,8 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.UI.Screens.Workshop.Parameters;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Routing;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
using StrawberryShake;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.Layout;
|
namespace Artemis.UI.Screens.Workshop.Layout;
|
||||||
|
|
||||||
public class LayoutDetailsViewModel : ActivatableViewModelBase
|
public class LayoutDetailsViewModel : RoutableScreen<ActivatableViewModelBase, WorkshopDetailParameters>, IWorkshopViewModel
|
||||||
{
|
{
|
||||||
|
private readonly IWorkshopClient _client;
|
||||||
|
private IGetEntryById_Entry? _entry;
|
||||||
|
|
||||||
|
public LayoutDetailsViewModel(IWorkshopClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntryType? EntryType => null;
|
||||||
|
|
||||||
|
public IGetEntryById_Entry? Entry
|
||||||
|
{
|
||||||
|
get => _entry;
|
||||||
|
set => RaiseAndSetIfChanged(ref _entry, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await GetEntry(parameters.EntryId, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetEntry(Guid entryId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
IOperationResult<IGetEntryByIdResult> result = await _client.GetEntryById.ExecuteAsync(entryId, cancellationToken);
|
||||||
|
if (result.IsErrorResult())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Entry = result.Data?.Entry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,15 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
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;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.Layout;
|
namespace Artemis.UI.Screens.Workshop.Layout;
|
||||||
|
|
||||||
public class LayoutListViewModel : RoutableScreen<ActivatableViewModelBase, WorkshopListParameters>, IMainScreenViewModel
|
public class LayoutListViewModel : RoutableScreen<ActivatableViewModelBase, WorkshopListParameters>, IWorkshopViewModel
|
||||||
{
|
{
|
||||||
private int _page;
|
private int _page;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public LayoutListViewModel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public int Page
|
public int Page
|
||||||
{
|
{
|
||||||
get => _page;
|
get => _page;
|
||||||
@ -22,5 +30,5 @@ public class LayoutListViewModel : RoutableScreen<ActivatableViewModelBase, Work
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ViewModelBase? TitleBarViewModel => null;
|
public EntryType? EntryType => WebClient.Workshop.EntryType.Layout;
|
||||||
}
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Parameters;
|
||||||
|
|
||||||
|
public class WorkshopDetailParameters
|
||||||
|
{
|
||||||
|
public Guid EntryId { get; set; }
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
namespace Artemis.UI.Screens.Workshop;
|
namespace Artemis.UI.Screens.Workshop.Parameters;
|
||||||
|
|
||||||
public class WorkshopListParameters
|
public class WorkshopListParameters
|
||||||
{
|
{
|
||||||
@ -2,7 +2,24 @@
|
|||||||
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:profile="clr-namespace:Artemis.UI.Screens.Workshop.Profile"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Workshop.Profile.ProfileDetailsView">
|
x:Class="Artemis.UI.Screens.Workshop.Profile.ProfileDetailsView"
|
||||||
Welcome to Avalonia!
|
x:DataType="profile:ProfileDetailsViewModel">
|
||||||
</UserControl>
|
<Border Classes="router-container">
|
||||||
|
<Grid ColumnDefinitions="300,*" RowDefinitions="Auto,*" Margin="10">
|
||||||
|
<StackPanel Grid.Row="0" Grid.ColumnSpan="2" >
|
||||||
|
<TextBlock Text="{CompiledBinding Entry.Name, FallbackValue=Profile}" Classes="h3 no-margin"/>
|
||||||
|
<TextBlock Text="{CompiledBinding Entry.Author, FallbackValue=Author}" Classes="subtitle" Margin="0 0 0 5"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Border Classes="card-condensed" Grid.Row="1" Grid.Column="0" Margin="0 0 10 0">
|
||||||
|
<TextBlock>Side panel</TextBlock>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Classes="card-condensed" Grid.Row="1" Grid.Column="1">
|
||||||
|
<TextBlock>Profile details panel</TextBlock>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
||||||
@ -1,8 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.UI.Screens.Workshop.Parameters;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Routing;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
using StrawberryShake;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.Profile;
|
namespace Artemis.UI.Screens.Workshop.Profile;
|
||||||
|
|
||||||
public class ProfileDetailsViewModel : ActivatableViewModelBase
|
public class ProfileDetailsViewModel : RoutableScreen<ActivatableViewModelBase, WorkshopDetailParameters>, IWorkshopViewModel
|
||||||
{
|
{
|
||||||
|
private readonly IWorkshopClient _client;
|
||||||
|
private IGetEntryById_Entry? _entry;
|
||||||
|
|
||||||
|
public ProfileDetailsViewModel(IWorkshopClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntryType? EntryType => null;
|
||||||
|
|
||||||
|
public IGetEntryById_Entry? Entry
|
||||||
|
{
|
||||||
|
get => _entry;
|
||||||
|
set => RaiseAndSetIfChanged(ref _entry, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await GetEntry(parameters.EntryId, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetEntry(Guid entryId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
IOperationResult<IGetEntryByIdResult> result = await _client.GetEntryById.ExecuteAsync(entryId, cancellationToken);
|
||||||
|
if (result.IsErrorResult())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Entry = result.Data?.Entry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,15 +1,24 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
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;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.Profile;
|
namespace Artemis.UI.Screens.Workshop.Profile;
|
||||||
|
|
||||||
public class ProfileListViewModel : RoutableScreen<ActivatableViewModelBase, WorkshopListParameters>, IMainScreenViewModel
|
public class ProfileListViewModel : RoutableScreen<ActivatableViewModelBase, WorkshopListParameters>, IWorkshopViewModel
|
||||||
{
|
{
|
||||||
private int _page;
|
private int _page;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ProfileListViewModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public int Page
|
public int Page
|
||||||
{
|
{
|
||||||
get => _page;
|
get => _page;
|
||||||
@ -21,6 +30,6 @@ public class ProfileListViewModel : RoutableScreen<ActivatableViewModelBase, Wor
|
|||||||
Page = Math.Max(1, parameters.Page);
|
Page = Math.Max(1, parameters.Page);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ViewModelBase? TitleBarViewModel => null;
|
public EntryType? EntryType => null;
|
||||||
}
|
}
|
||||||
55
src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml
Normal file
55
src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<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:search="clr-namespace:Artemis.UI.Screens.Workshop.Search"
|
||||||
|
xmlns:workshop="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop"
|
||||||
|
xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.Search.SearchView"
|
||||||
|
x:DataType="search:SearchViewModel">
|
||||||
|
<UserControl.Styles>
|
||||||
|
<StyleInclude Source="SearchViewStyles.axaml" />
|
||||||
|
</UserControl.Styles>
|
||||||
|
<Panel>
|
||||||
|
<AutoCompleteBox Name="SearchBox"
|
||||||
|
MaxWidth="500"
|
||||||
|
Watermark="Search"
|
||||||
|
Margin="0 5"
|
||||||
|
ValueMemberBinding="{CompiledBinding Name, DataType=workshop:ISearchEntries_Entries_Nodes}"
|
||||||
|
AsyncPopulator="{CompiledBinding SearchAsync}"
|
||||||
|
SelectedItem="{CompiledBinding SelectedEntry}"
|
||||||
|
FilterMode="None"
|
||||||
|
windowing:AppWindow.AllowInteractionInTitleBar="True">
|
||||||
|
<AutoCompleteBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="workshop:ISearchEntries_Entries_Nodes">
|
||||||
|
<Panel>
|
||||||
|
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="{CompiledBinding Name}" />
|
||||||
|
<TextBlock Text="{CompiledBinding Summary}" Foreground="{DynamicResource TextFillColorSecondary}" />
|
||||||
|
|
||||||
|
<ItemsControl ItemsSource="{CompiledBinding Categories}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="5"></StackPanel>
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border Classes="category">
|
||||||
|
<TextBlock Text="{CompiledBinding Name}"></TextBlock>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
</Panel>
|
||||||
|
</DataTemplate>
|
||||||
|
</AutoCompleteBox.ItemTemplate>
|
||||||
|
</AutoCompleteBox>
|
||||||
|
<ContentControl HorizontalAlignment="Right"
|
||||||
|
Margin="0 0 50 0"
|
||||||
|
Content="{CompiledBinding CurrentUserViewModel}"
|
||||||
|
windowing:AppWindow.AllowInteractionInTitleBar="True"/>
|
||||||
|
</Panel>
|
||||||
|
</UserControl>
|
||||||
18
src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml.cs
Normal file
18
src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Search;
|
||||||
|
|
||||||
|
public partial class SearchView : UserControl
|
||||||
|
{
|
||||||
|
public SearchView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
80
src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs
Normal file
80
src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.UI.Screens.Workshop.CurrentUser;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Routing;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
using ReactiveUI;
|
||||||
|
using StrawberryShake;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.Search;
|
||||||
|
|
||||||
|
public class SearchViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
public CurrentUserViewModel CurrentUserViewModel { get; }
|
||||||
|
private readonly IRouter _router;
|
||||||
|
private readonly IWorkshopClient _workshopClient;
|
||||||
|
private EntryType? _entryType;
|
||||||
|
private ISearchEntries_Entries_Nodes? _selectedEntry;
|
||||||
|
|
||||||
|
public SearchViewModel(IWorkshopClient workshopClient, IRouter router, CurrentUserViewModel currentUserViewModel)
|
||||||
|
{
|
||||||
|
CurrentUserViewModel = currentUserViewModel;
|
||||||
|
_workshopClient = workshopClient;
|
||||||
|
_router = router;
|
||||||
|
SearchAsync = ExecuteSearchAsync;
|
||||||
|
|
||||||
|
this.WhenAnyValue(vm => vm.SelectedEntry).WhereNotNull().Subscribe(NavigateToEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<string?, CancellationToken, Task<IEnumerable<object>>> SearchAsync { get; }
|
||||||
|
|
||||||
|
public ISearchEntries_Entries_Nodes? SelectedEntry
|
||||||
|
{
|
||||||
|
get => _selectedEntry;
|
||||||
|
set => RaiseAndSetIfChanged(ref _selectedEntry, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntryType? EntryType
|
||||||
|
{
|
||||||
|
get => _entryType;
|
||||||
|
set => RaiseAndSetIfChanged(ref _entryType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NavigateToEntry(ISearchEntries_Entries_Nodes entry)
|
||||||
|
{
|
||||||
|
string? url = null;
|
||||||
|
if (entry.EntryType == WebClient.Workshop.EntryType.Profile)
|
||||||
|
url = $"workshop/profiles/{entry.Id}";
|
||||||
|
if (entry.EntryType == WebClient.Workshop.EntryType.Layout)
|
||||||
|
url = $"workshop/layouts/{entry.Id}";
|
||||||
|
|
||||||
|
if (url != null)
|
||||||
|
Task.Run(() => _router.Navigate(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<object>> ExecuteSearchAsync(string? input, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
|
return new List<object>();
|
||||||
|
|
||||||
|
EntryFilterInput filter;
|
||||||
|
if (EntryType != null)
|
||||||
|
filter = new EntryFilterInput
|
||||||
|
{
|
||||||
|
And = new[]
|
||||||
|
{
|
||||||
|
new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = EntryType}},
|
||||||
|
new EntryFilterInput {Name = new StringOperationFilterInput {Contains = input}}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
else
|
||||||
|
filter = new EntryFilterInput {Name = new StringOperationFilterInput {Contains = input}};
|
||||||
|
|
||||||
|
IOperationResult<ISearchEntriesResult> results = await _workshopClient.SearchEntries.ExecuteAsync(filter, cancellationToken);
|
||||||
|
return results.Data?.Entries?.Nodes?.Cast<object>() ?? new List<object>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
<Styles xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<Design.PreviewWith>
|
||||||
|
<Border Padding="10">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||||
|
<Border Classes="category">
|
||||||
|
<TextBlock Text="Media"></TextBlock>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Classes="category">
|
||||||
|
<TextBlock Text="Audio"></TextBlock>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Classes="category">
|
||||||
|
<TextBlock Text="Interaction"></TextBlock>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Design.PreviewWith>
|
||||||
|
|
||||||
|
<!-- Add Styles Here -->
|
||||||
|
<Style Selector="Border.category">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource ControlSolidFillColorDefaultBrush}" />
|
||||||
|
<Setter Property="CornerRadius" Value="12" />
|
||||||
|
<Setter Property="Padding" Value="6 1"></Setter>
|
||||||
|
<Setter Property="TextBlock.FontSize" Value="12" />
|
||||||
|
</Style>
|
||||||
|
</Styles>
|
||||||
@ -8,7 +8,9 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800"
|
mc:Ignorable="d" d:DesignWidth="800"
|
||||||
x:Class="Artemis.UI.Screens.Workshop.WorkshopView"
|
x:Class="Artemis.UI.Screens.Workshop.WorkshopView"
|
||||||
x:DataType="workshop:WorkshopViewModel">
|
x:DataType="workshop:WorkshopViewModel">
|
||||||
<Border Classes="router-container">
|
<controls:Frame Name="WorkshopFrame" IsNavigationStackEnabled="False" CacheSize="0">
|
||||||
<TextBlock>Workshop overview</TextBlock>
|
<controls:Frame.NavigationPageFactory>
|
||||||
</Border>
|
<ui:PageFactory/>
|
||||||
|
</controls:Frame.NavigationPageFactory>
|
||||||
|
</controls:Frame>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,4 +1,8 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop;
|
namespace Artemis.UI.Screens.Workshop;
|
||||||
|
|
||||||
@ -7,5 +11,6 @@ public partial class WorkshopView : ReactiveUserControl<WorkshopViewModel>
|
|||||||
public WorkshopView()
|
public WorkshopView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen).Subscribe(vm => WorkshopFrame.NavigateFromObject(vm ?? ViewModel?.HomeViewModel)).DisposeWith(d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,13 +1,38 @@
|
|||||||
using Artemis.UI.Shared;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.UI.Screens.Workshop.Home;
|
||||||
|
using Artemis.UI.Screens.Workshop.Search;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop;
|
namespace Artemis.UI.Screens.Workshop;
|
||||||
|
|
||||||
public class WorkshopViewModel : RoutableScreen<object>, IMainScreenViewModel
|
public class WorkshopViewModel : RoutableScreen<IWorkshopViewModel>, IMainScreenViewModel
|
||||||
{
|
{
|
||||||
public WorkshopViewModel()
|
private readonly SearchViewModel _searchViewModel;
|
||||||
|
|
||||||
|
public WorkshopViewModel(SearchViewModel searchViewModel, WorkshopHomeViewModel homeViewModel)
|
||||||
{
|
{
|
||||||
|
_searchViewModel = searchViewModel;
|
||||||
|
|
||||||
|
TitleBarViewModel = searchViewModel;
|
||||||
|
HomeViewModel = homeViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ViewModelBase? TitleBarViewModel => null;
|
public ViewModelBase TitleBarViewModel { get; }
|
||||||
|
public WorkshopHomeViewModel HomeViewModel { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task OnNavigating(NavigationArguments args, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_searchViewModel.EntryType = Screen?.EntryType;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IWorkshopViewModel
|
||||||
|
{
|
||||||
|
public EntryType? EntryType { get; }
|
||||||
}
|
}
|
||||||
@ -22,4 +22,13 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<GraphQL Update="Queries\SearchEntries.graphql">
|
||||||
|
<Generator>MSBuild:GenerateGraphQLCode</Generator>
|
||||||
|
</GraphQL>
|
||||||
|
<GraphQL Update="Queries\GetCategories.graphql">
|
||||||
|
<Generator>MSBuild:GenerateGraphQLCode</Generator>
|
||||||
|
</GraphQL>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
query GetCategories {
|
||||||
|
categories {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
icon
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql
Normal file
18
src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
query SearchEntries($filter: EntryFilterInput) {
|
||||||
|
entries(
|
||||||
|
first: 10
|
||||||
|
where: $filter
|
||||||
|
) {
|
||||||
|
nodes {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
summary
|
||||||
|
entryType
|
||||||
|
categories {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
icon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,12 @@ schema {
|
|||||||
mutation: Mutation
|
mutation: Mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Category {
|
||||||
|
icon: String!
|
||||||
|
id: Int!
|
||||||
|
name: String!
|
||||||
|
}
|
||||||
|
|
||||||
"A connection to a list of items."
|
"A connection to a list of items."
|
||||||
type EntriesConnection {
|
type EntriesConnection {
|
||||||
"A list of edges."
|
"A list of edges."
|
||||||
@ -27,14 +33,18 @@ type EntriesEdge {
|
|||||||
|
|
||||||
type Entry {
|
type Entry {
|
||||||
author: UUID!
|
author: UUID!
|
||||||
|
categories: [Category!]!
|
||||||
|
createdAt: DateTime!
|
||||||
description: String!
|
description: String!
|
||||||
|
downloads: Long!
|
||||||
entryType: EntryType!
|
entryType: EntryType!
|
||||||
icon: Image
|
icon: Image
|
||||||
id: UUID!
|
id: UUID!
|
||||||
images: [Image!]!
|
images: [Image!]!
|
||||||
name: String!
|
name: String!
|
||||||
releases: [Release!]!
|
releases: [Release!]!
|
||||||
tags: [String!]!
|
summary: String!
|
||||||
|
tags: [Tag!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Image {
|
type Image {
|
||||||
@ -59,6 +69,7 @@ type PageInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
|
categories(order: [CategorySortInput!], where: CategoryFilterInput): [Category!]!
|
||||||
entries(
|
entries(
|
||||||
"Returns the elements in the list that come after the specified cursor."
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
after: String,
|
after: String,
|
||||||
@ -78,11 +89,17 @@ type Release {
|
|||||||
createdAt: DateTime!
|
createdAt: DateTime!
|
||||||
downloadSize: Long!
|
downloadSize: Long!
|
||||||
downloads: Long!
|
downloads: Long!
|
||||||
|
entry: Entry!
|
||||||
id: UUID!
|
id: UUID!
|
||||||
md5Hash: String
|
md5Hash: String
|
||||||
version: String!
|
version: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Tag {
|
||||||
|
id: Int!
|
||||||
|
name: String!
|
||||||
|
}
|
||||||
|
|
||||||
enum EntryType {
|
enum EntryType {
|
||||||
LAYOUT
|
LAYOUT
|
||||||
PLUGIN
|
PLUGIN
|
||||||
@ -102,6 +119,20 @@ scalar Long
|
|||||||
|
|
||||||
scalar UUID
|
scalar UUID
|
||||||
|
|
||||||
|
input CategoryFilterInput {
|
||||||
|
and: [CategoryFilterInput!]
|
||||||
|
icon: StringOperationFilterInput
|
||||||
|
id: IntOperationFilterInput
|
||||||
|
name: StringOperationFilterInput
|
||||||
|
or: [CategoryFilterInput!]
|
||||||
|
}
|
||||||
|
|
||||||
|
input CategorySortInput {
|
||||||
|
icon: SortEnumType
|
||||||
|
id: SortEnumType
|
||||||
|
name: SortEnumType
|
||||||
|
}
|
||||||
|
|
||||||
input DateTimeOperationFilterInput {
|
input DateTimeOperationFilterInput {
|
||||||
eq: DateTime
|
eq: DateTime
|
||||||
gt: DateTime
|
gt: DateTime
|
||||||
@ -120,7 +151,10 @@ input DateTimeOperationFilterInput {
|
|||||||
input EntryFilterInput {
|
input EntryFilterInput {
|
||||||
and: [EntryFilterInput!]
|
and: [EntryFilterInput!]
|
||||||
author: UuidOperationFilterInput
|
author: UuidOperationFilterInput
|
||||||
|
categories: ListFilterInputTypeOfCategoryFilterInput
|
||||||
|
createdAt: DateTimeOperationFilterInput
|
||||||
description: StringOperationFilterInput
|
description: StringOperationFilterInput
|
||||||
|
downloads: LongOperationFilterInput
|
||||||
entryType: EntryTypeOperationFilterInput
|
entryType: EntryTypeOperationFilterInput
|
||||||
icon: ImageFilterInput
|
icon: ImageFilterInput
|
||||||
id: UuidOperationFilterInput
|
id: UuidOperationFilterInput
|
||||||
@ -128,7 +162,8 @@ input EntryFilterInput {
|
|||||||
name: StringOperationFilterInput
|
name: StringOperationFilterInput
|
||||||
or: [EntryFilterInput!]
|
or: [EntryFilterInput!]
|
||||||
releases: ListFilterInputTypeOfReleaseFilterInput
|
releases: ListFilterInputTypeOfReleaseFilterInput
|
||||||
tags: ListStringOperationFilterInput
|
summary: StringOperationFilterInput
|
||||||
|
tags: ListFilterInputTypeOfTagFilterInput
|
||||||
}
|
}
|
||||||
|
|
||||||
input EntryInput {
|
input EntryInput {
|
||||||
@ -140,11 +175,14 @@ input EntryInput {
|
|||||||
|
|
||||||
input EntrySortInput {
|
input EntrySortInput {
|
||||||
author: SortEnumType
|
author: SortEnumType
|
||||||
|
createdAt: SortEnumType
|
||||||
description: SortEnumType
|
description: SortEnumType
|
||||||
|
downloads: SortEnumType
|
||||||
entryType: SortEnumType
|
entryType: SortEnumType
|
||||||
icon: ImageSortInput
|
icon: ImageSortInput
|
||||||
id: SortEnumType
|
id: SortEnumType
|
||||||
name: SortEnumType
|
name: SortEnumType
|
||||||
|
summary: SortEnumType
|
||||||
}
|
}
|
||||||
|
|
||||||
input EntryTypeOperationFilterInput {
|
input EntryTypeOperationFilterInput {
|
||||||
@ -166,6 +204,28 @@ input ImageSortInput {
|
|||||||
mimeType: SortEnumType
|
mimeType: SortEnumType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input IntOperationFilterInput {
|
||||||
|
eq: Int
|
||||||
|
gt: Int
|
||||||
|
gte: Int
|
||||||
|
in: [Int]
|
||||||
|
lt: Int
|
||||||
|
lte: Int
|
||||||
|
neq: Int
|
||||||
|
ngt: Int
|
||||||
|
ngte: Int
|
||||||
|
nin: [Int]
|
||||||
|
nlt: Int
|
||||||
|
nlte: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
input ListFilterInputTypeOfCategoryFilterInput {
|
||||||
|
all: CategoryFilterInput
|
||||||
|
any: Boolean
|
||||||
|
none: CategoryFilterInput
|
||||||
|
some: CategoryFilterInput
|
||||||
|
}
|
||||||
|
|
||||||
input ListFilterInputTypeOfImageFilterInput {
|
input ListFilterInputTypeOfImageFilterInput {
|
||||||
all: ImageFilterInput
|
all: ImageFilterInput
|
||||||
any: Boolean
|
any: Boolean
|
||||||
@ -180,11 +240,11 @@ input ListFilterInputTypeOfReleaseFilterInput {
|
|||||||
some: ReleaseFilterInput
|
some: ReleaseFilterInput
|
||||||
}
|
}
|
||||||
|
|
||||||
input ListStringOperationFilterInput {
|
input ListFilterInputTypeOfTagFilterInput {
|
||||||
all: StringOperationFilterInput
|
all: TagFilterInput
|
||||||
any: Boolean
|
any: Boolean
|
||||||
none: StringOperationFilterInput
|
none: TagFilterInput
|
||||||
some: StringOperationFilterInput
|
some: TagFilterInput
|
||||||
}
|
}
|
||||||
|
|
||||||
input LongOperationFilterInput {
|
input LongOperationFilterInput {
|
||||||
@ -207,6 +267,7 @@ input ReleaseFilterInput {
|
|||||||
createdAt: DateTimeOperationFilterInput
|
createdAt: DateTimeOperationFilterInput
|
||||||
downloadSize: LongOperationFilterInput
|
downloadSize: LongOperationFilterInput
|
||||||
downloads: LongOperationFilterInput
|
downloads: LongOperationFilterInput
|
||||||
|
entry: EntryFilterInput
|
||||||
id: UuidOperationFilterInput
|
id: UuidOperationFilterInput
|
||||||
md5Hash: StringOperationFilterInput
|
md5Hash: StringOperationFilterInput
|
||||||
or: [ReleaseFilterInput!]
|
or: [ReleaseFilterInput!]
|
||||||
@ -228,6 +289,13 @@ input StringOperationFilterInput {
|
|||||||
startsWith: String
|
startsWith: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input TagFilterInput {
|
||||||
|
and: [TagFilterInput!]
|
||||||
|
id: IntOperationFilterInput
|
||||||
|
name: StringOperationFilterInput
|
||||||
|
or: [TagFilterInput!]
|
||||||
|
}
|
||||||
|
|
||||||
input UuidOperationFilterInput {
|
input UuidOperationFilterInput {
|
||||||
eq: UUID
|
eq: UUID
|
||||||
gt: UUID
|
gt: UUID
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user