mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Workshop - Improve child navigation performance
This commit is contained in:
parent
cac44d748d
commit
62057d657a
@ -9,5 +9,6 @@ internal interface IRoutableHostScreen : IRoutableScreen
|
|||||||
{
|
{
|
||||||
bool RecycleScreen { get; }
|
bool RecycleScreen { get; }
|
||||||
IRoutableScreen? InternalScreen { get; }
|
IRoutableScreen? InternalScreen { get; }
|
||||||
|
IRoutableScreen? InternalDefaultScreen { get; }
|
||||||
void InternalChangeScreen(IRoutableScreen? screen);
|
void InternalChangeScreen(IRoutableScreen? screen);
|
||||||
}
|
}
|
||||||
@ -25,7 +25,13 @@ public abstract class RoutableHostScreen<TScreen> : RoutableScreen, IRoutableHos
|
|||||||
protected set => RaiseAndSetIfChanged(ref _recycleScreen, value);
|
protected set => RaiseAndSetIfChanged(ref _recycleScreen, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the screen to show when no other screen is active.
|
||||||
|
/// </summary>
|
||||||
|
public virtual TScreen? DefaultScreen { get; }
|
||||||
|
|
||||||
IRoutableScreen? IRoutableHostScreen.InternalScreen => Screen;
|
IRoutableScreen? IRoutableHostScreen.InternalScreen => Screen;
|
||||||
|
IRoutableScreen? IRoutableHostScreen.InternalDefaultScreen => DefaultScreen;
|
||||||
|
|
||||||
void IRoutableHostScreen.InternalChangeScreen(IRoutableScreen? screen)
|
void IRoutableHostScreen.InternalChangeScreen(IRoutableScreen? screen)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -27,7 +27,13 @@ public abstract class RoutableHostScreen<TScreen, TParam> : RoutableScreen<TPara
|
|||||||
protected set => RaiseAndSetIfChanged(ref _recycleScreen, value);
|
protected set => RaiseAndSetIfChanged(ref _recycleScreen, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the screen to show when no other screen is active.
|
||||||
|
/// </summary>
|
||||||
|
public virtual TScreen? DefaultScreen { get; }
|
||||||
|
|
||||||
IRoutableScreen? IRoutableHostScreen.InternalScreen => Screen;
|
IRoutableScreen? IRoutableHostScreen.InternalScreen => Screen;
|
||||||
|
IRoutableScreen? IRoutableHostScreen.InternalDefaultScreen => DefaultScreen;
|
||||||
|
|
||||||
void IRoutableHostScreen.InternalChangeScreen(IRoutableScreen? screen)
|
void IRoutableHostScreen.InternalChangeScreen(IRoutableScreen? screen)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -109,12 +109,11 @@ internal class Navigation
|
|||||||
// Navigate the child too
|
// Navigate the child too
|
||||||
if (resolution.Child != null)
|
if (resolution.Child != null)
|
||||||
await NavigateResolution(resolution.Child, args, childScreen);
|
await NavigateResolution(resolution.Child, args, childScreen);
|
||||||
// Make sure there is no child
|
// Without a resolution, navigate to the default screen (which may be null)
|
||||||
else if (childScreen.InternalScreen != null)
|
else if (childScreen.InternalScreen != childScreen.InternalDefaultScreen)
|
||||||
childScreen.InternalChangeScreen(null);
|
childScreen.InternalChangeScreen(childScreen.InternalDefaultScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Completed = true;
|
Completed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="20" Grid.Column="0">
|
<Grid Margin="20" Grid.Column="0">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
|
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">TitleTextBlockStyle</TextBlock>
|
||||||
<TextBlock Classes="h1">This is heading 1</TextBlock>
|
<TextBlock Classes="h1">This is heading 1</TextBlock>
|
||||||
<TextBlock Classes="h2">This is heading 2</TextBlock>
|
<TextBlock Classes="h2">This is heading 2</TextBlock>
|
||||||
<TextBlock Classes="h3">This is heading 3</TextBlock>
|
<TextBlock Classes="h3">This is heading 3</TextBlock>
|
||||||
@ -22,6 +23,7 @@
|
|||||||
|
|
||||||
<Grid Margin="20" Grid.Column="1">
|
<Grid Margin="20" Grid.Column="1">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
|
<Border Width="400" Classes="skeleton-text title"></Border>
|
||||||
<Border Width="400" Classes="skeleton-text h1"></Border>
|
<Border Width="400" Classes="skeleton-text h1"></Border>
|
||||||
<Border Width="400" Classes="skeleton-text h2"></Border>
|
<Border Width="400" Classes="skeleton-text h2"></Border>
|
||||||
<Border Width="400" Classes="skeleton-text h3"></Border>
|
<Border Width="400" Classes="skeleton-text h3"></Border>
|
||||||
@ -39,6 +41,7 @@
|
|||||||
<Setter Property="Background" Value="#55ff0000"></Setter>
|
<Setter Property="Background" Value="#55ff0000"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
</StackPanel.Styles>
|
</StackPanel.Styles>
|
||||||
|
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">TitleTextBlockStyle</TextBlock>
|
||||||
<TextBlock Classes="h1">This is heading 1</TextBlock>
|
<TextBlock Classes="h1">This is heading 1</TextBlock>
|
||||||
<TextBlock Classes="h2">This is heading 2</TextBlock>
|
<TextBlock Classes="h2">This is heading 2</TextBlock>
|
||||||
<TextBlock Classes="h3">This is heading 3</TextBlock>
|
<TextBlock Classes="h3">This is heading 3</TextBlock>
|
||||||
@ -51,6 +54,7 @@
|
|||||||
|
|
||||||
<Grid Margin="20" Grid.Column="0" Row="1">
|
<Grid Margin="20" Grid.Column="0" Row="1">
|
||||||
<StackPanel Spacing="2">
|
<StackPanel Spacing="2">
|
||||||
|
<Border Width="400" Classes="skeleton-text title no-margin"></Border>
|
||||||
<Border Width="400" Classes="skeleton-text h1 no-margin"></Border>
|
<Border Width="400" Classes="skeleton-text h1 no-margin"></Border>
|
||||||
<Border Width="400" Classes="skeleton-text h2 no-margin"></Border>
|
<Border Width="400" Classes="skeleton-text h2 no-margin"></Border>
|
||||||
<Border Width="400" Classes="skeleton-text h3 no-margin"></Border>
|
<Border Width="400" Classes="skeleton-text h3 no-margin"></Border>
|
||||||
@ -68,6 +72,7 @@
|
|||||||
<Setter Property="Background" Value="#55ff0000"></Setter>
|
<Setter Property="Background" Value="#55ff0000"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
</StackPanel.Styles>
|
</StackPanel.Styles>
|
||||||
|
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">TitleTextBlockStyle</TextBlock>
|
||||||
<TextBlock Classes="h1 no-margin">This is heading 1</TextBlock>
|
<TextBlock Classes="h1 no-margin">This is heading 1</TextBlock>
|
||||||
<TextBlock Classes="h2 no-margin">This is heading 2</TextBlock>
|
<TextBlock Classes="h2 no-margin">This is heading 2</TextBlock>
|
||||||
<TextBlock Classes="h3 no-margin">This is heading 3</TextBlock>
|
<TextBlock Classes="h3 no-margin">This is heading 3</TextBlock>
|
||||||
@ -125,6 +130,11 @@
|
|||||||
</Style.Animations>
|
</Style.Animations>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Border.skeleton-text.title">
|
||||||
|
<Setter Property="Height" Value="28" />
|
||||||
|
<Setter Property="Margin" Value="0 5 0 5" />
|
||||||
|
<Setter Property="CornerRadius" Value="8" />
|
||||||
|
</Style>
|
||||||
<Style Selector="Border.skeleton-text.h1">
|
<Style Selector="Border.skeleton-text.h1">
|
||||||
<Setter Property="Height" Value="65" />
|
<Setter Property="Height" Value="65" />
|
||||||
<Setter Property="Margin" Value="0 10 0 20" />
|
<Setter Property="Margin" Value="0 10 0 20" />
|
||||||
|
|||||||
@ -13,7 +13,22 @@
|
|||||||
<converters:EntryIconUriConverter x:Key="EntryIconUriConverter" />
|
<converters:EntryIconUriConverter x:Key="EntryIconUriConverter" />
|
||||||
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<StackPanel>
|
<Panel>
|
||||||
|
<StackPanel IsVisible="{CompiledBinding Entry, Converter={x:Static ObjectConverters.IsNull}}">
|
||||||
|
<Border Classes="skeleton-text" Margin="0 0 10 0" Width="80" Height="80"></Border>
|
||||||
|
<Border Classes="skeleton-text title" HorizontalAlignment="Stretch"/>
|
||||||
|
<Border Classes="skeleton-text" Width="120"/>
|
||||||
|
<Border Classes="skeleton-text" Width="140" Margin="0 8"/>
|
||||||
|
<Border Classes="skeleton-text" Width="80"/>
|
||||||
|
<Border Classes="card-separator" Margin="0 15 0 17"></Border>
|
||||||
|
<Border Classes="skeleton-text" Width="120"/>
|
||||||
|
<StackPanel Margin="0 10 0 0">
|
||||||
|
<Border Classes="skeleton-text" Width="160"/>
|
||||||
|
<Border Classes="skeleton-text" Width="160"/>
|
||||||
|
</StackPanel>
|
||||||
|
<Border Classes="skeleton-button"></Border>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel IsVisible="{CompiledBinding Entry, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
<Panel>
|
<Panel>
|
||||||
<Border CornerRadius="6"
|
<Border CornerRadius="6"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
@ -35,7 +50,7 @@
|
|||||||
<TextBlock Theme="{StaticResource TitleTextBlockStyle}"
|
<TextBlock Theme="{StaticResource TitleTextBlockStyle}"
|
||||||
MaxLines="3"
|
MaxLines="3"
|
||||||
TextTrimming="CharacterEllipsis"
|
TextTrimming="CharacterEllipsis"
|
||||||
Text="{CompiledBinding Entry.Name, FallbackValue=Title }" />
|
Text="{CompiledBinding Entry.Name, FallbackValue=Title}"/>
|
||||||
|
|
||||||
<TextBlock Classes="subtitle" TextTrimming="CharacterEllipsis" Text="{CompiledBinding Entry.Author, FallbackValue=Author}" />
|
<TextBlock Classes="subtitle" TextTrimming="CharacterEllipsis" Text="{CompiledBinding Entry.Author, FallbackValue=Author}" />
|
||||||
|
|
||||||
@ -83,4 +98,5 @@
|
|||||||
Manage installation
|
Manage installation
|
||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
</Panel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -8,6 +8,7 @@ using Artemis.UI.Shared;
|
|||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
|
using Artemis.WebClient.Workshop.Extensions;
|
||||||
using Artemis.WebClient.Workshop.Models;
|
using Artemis.WebClient.Workshop.Models;
|
||||||
using Artemis.WebClient.Workshop.Services;
|
using Artemis.WebClient.Workshop.Services;
|
||||||
using PropertyChanged.SourceGenerator;
|
using PropertyChanged.SourceGenerator;
|
||||||
@ -19,36 +20,47 @@ public partial class EntryInfoViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
private readonly IRouter _router;
|
private readonly IRouter _router;
|
||||||
private readonly INotificationService _notificationService;
|
private readonly INotificationService _notificationService;
|
||||||
|
private readonly IWorkshopService _workshopService;
|
||||||
|
[Notify] private IEntryDetails? _entry;
|
||||||
|
[Notify] private DateTimeOffset? _updatedAt;
|
||||||
[Notify] private bool _canBeManaged;
|
[Notify] private bool _canBeManaged;
|
||||||
|
|
||||||
public EntryInfoViewModel(IEntryDetails entry, IRouter router, INotificationService notificationService, IWorkshopService workshopService)
|
public EntryInfoViewModel(IRouter router, INotificationService notificationService, IWorkshopService workshopService)
|
||||||
{
|
{
|
||||||
_router = router;
|
_router = router;
|
||||||
_notificationService = notificationService;
|
_notificationService = notificationService;
|
||||||
Entry = entry;
|
_workshopService = workshopService;
|
||||||
UpdatedAt = Entry.Releases.Any() ? Entry.Releases.Max(r => r.CreatedAt) : Entry.CreatedAt;
|
|
||||||
CanBeManaged = Entry.EntryType != EntryType.Profile && workshopService.GetInstalledEntry(entry.Id) != null;
|
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
Observable.FromEventPattern<InstalledEntry>(x => workshopService.OnInstalledEntrySaved += x, x => workshopService.OnInstalledEntrySaved -= x)
|
Observable.FromEventPattern<InstalledEntry>(x => workshopService.OnInstalledEntrySaved += x, x => workshopService.OnInstalledEntrySaved -= x)
|
||||||
.StartWith([])
|
.StartWith([])
|
||||||
.Subscribe(_ => CanBeManaged = Entry.EntryType != EntryType.Profile && workshopService.GetInstalledEntry(entry.Id) != null)
|
.Subscribe(_ => CanBeManaged = Entry != null && Entry.EntryType != EntryType.Profile && workshopService.GetInstalledEntry(Entry.Id) != null)
|
||||||
.DisposeWith(d);
|
.DisposeWith(d);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEntryDetails Entry { get; }
|
public void SetEntry(IEntryDetails? entry)
|
||||||
public DateTimeOffset? UpdatedAt { get; }
|
{
|
||||||
|
Entry = entry;
|
||||||
|
UpdatedAt = Entry != null && Entry.Releases.Any() ? Entry.Releases.Max(r => r.CreatedAt) : Entry?.CreatedAt;
|
||||||
|
CanBeManaged = Entry != null && Entry.EntryType != EntryType.Profile && _workshopService.GetInstalledEntry(Entry.Id) != null;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task CopyShareLink()
|
public async Task CopyShareLink()
|
||||||
{
|
{
|
||||||
|
if (Entry == null)
|
||||||
|
return;
|
||||||
|
|
||||||
await Shared.UI.Clipboard.SetTextAsync($"{WorkshopConstants.WORKSHOP_URL}/entries/{Entry.Id}/{StringUtilities.UrlFriendly(Entry.Name)}");
|
await Shared.UI.Clipboard.SetTextAsync($"{WorkshopConstants.WORKSHOP_URL}/entries/{Entry.Id}/{StringUtilities.UrlFriendly(Entry.Name)}");
|
||||||
_notificationService.CreateNotification().WithTitle("Copied share link to clipboard.").Show();
|
_notificationService.CreateNotification().WithTitle("Copied share link to clipboard.").Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GoToManage()
|
public async Task GoToManage()
|
||||||
{
|
{
|
||||||
await _router.Navigate("/manage");
|
if (Entry == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await _router.Navigate($"{Entry.GetEntryPath()}/manage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||||||
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 Artemis.WebClient.Workshop.Extensions;
|
||||||
using PropertyChanged.SourceGenerator;
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
@ -25,14 +26,15 @@ public partial class EntryReleasesViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
router.CurrentPath.Subscribe(p => SelectedRelease = p != null && p.Contains("releases") && float.TryParse(p.Split('/').Last(), out float releaseId)
|
router.CurrentPath.Subscribe(p =>
|
||||||
|
SelectedRelease = p != null && p.StartsWith(Entry.GetEntryPath()) && float.TryParse(p.Split('/').Last(), out float releaseId)
|
||||||
? Releases.FirstOrDefault(r => r.Release.Id == releaseId)
|
? Releases.FirstOrDefault(r => r.Release.Id == releaseId)
|
||||||
: null)
|
: null)
|
||||||
.DisposeWith(d);
|
.DisposeWith(d);
|
||||||
|
|
||||||
this.WhenAnyValue(vm => vm.SelectedRelease)
|
this.WhenAnyValue(vm => vm.SelectedRelease)
|
||||||
.WhereNotNull()
|
.WhereNotNull()
|
||||||
.Subscribe(s => _router.Navigate($"/releases/{s.Release.Id}"))
|
.Subscribe(s => _router.Navigate($"{Entry.GetEntryPath()}/releases/{s.Release.Id}"))
|
||||||
.DisposeWith(d);
|
.DisposeWith(d);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
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:layout="clr-namespace:Artemis.UI.Screens.Workshop.Layout"
|
xmlns:layout="clr-namespace:Artemis.UI.Screens.Workshop.Layout"
|
||||||
xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight"
|
|
||||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:ui="clr-namespace:Artemis.UI"
|
xmlns:ui="clr-namespace:Artemis.UI"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800"
|
||||||
@ -14,7 +13,7 @@
|
|||||||
<Border Classes="card" VerticalAlignment="Top">
|
<Border Classes="card" VerticalAlignment="Top">
|
||||||
<ContentControl Content="{CompiledBinding EntryInfoViewModel}" />
|
<ContentControl Content="{CompiledBinding EntryInfoViewModel}" />
|
||||||
</Border>
|
</Border>
|
||||||
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Entry.Releases.Count}">
|
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Entry.Releases.Count, FallbackValue=False}">
|
||||||
<ContentControl Content="{CompiledBinding EntryReleasesViewModel}" />
|
<ContentControl Content="{CompiledBinding EntryReleasesViewModel}" />
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@ -11,7 +11,8 @@ public partial class LayoutDetailsView : ReactiveUserControl<LayoutDetailsViewMo
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
||||||
.Subscribe(screen => RouterFrame.NavigateFromObject(screen ?? ViewModel?.LayoutDescriptionViewModel))
|
.WhereNotNull()
|
||||||
|
.Subscribe(screen => RouterFrame.NavigateFromObject(screen))
|
||||||
.DisposeWith(d));
|
.DisposeWith(d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14,30 +14,30 @@ namespace Artemis.UI.Screens.Workshop.Layout;
|
|||||||
public partial class LayoutDetailsViewModel : RoutableHostScreen<RoutableScreen, WorkshopDetailParameters>
|
public partial class LayoutDetailsViewModel : RoutableHostScreen<RoutableScreen, WorkshopDetailParameters>
|
||||||
{
|
{
|
||||||
private readonly IWorkshopClient _client;
|
private readonly IWorkshopClient _client;
|
||||||
private readonly Func<IEntryDetails, EntryInfoViewModel> _getEntryInfoViewModel;
|
private readonly LayoutDescriptionViewModel _layoutDescriptionViewModel;
|
||||||
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
||||||
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
|
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
|
||||||
[Notify] private IEntryDetails? _entry;
|
[Notify] private IEntryDetails? _entry;
|
||||||
[Notify] private EntryInfoViewModel? _entryInfoViewModel;
|
|
||||||
[Notify] private EntryReleasesViewModel? _entryReleasesViewModel;
|
[Notify] private EntryReleasesViewModel? _entryReleasesViewModel;
|
||||||
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
|
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
|
||||||
|
|
||||||
public LayoutDetailsViewModel(IWorkshopClient client,
|
public LayoutDetailsViewModel(IWorkshopClient client,
|
||||||
LayoutDescriptionViewModel layoutDescriptionViewModel,
|
LayoutDescriptionViewModel layoutDescriptionViewModel,
|
||||||
Func<IEntryDetails, EntryInfoViewModel> getEntryInfoViewModel,
|
EntryInfoViewModel entryInfoViewModel,
|
||||||
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
|
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
|
||||||
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel)
|
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_getEntryInfoViewModel = getEntryInfoViewModel;
|
_layoutDescriptionViewModel = layoutDescriptionViewModel;
|
||||||
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
||||||
_getEntryImagesViewModel = getEntryImagesViewModel;
|
_getEntryImagesViewModel = getEntryImagesViewModel;
|
||||||
|
|
||||||
LayoutDescriptionViewModel = layoutDescriptionViewModel;
|
|
||||||
RecycleScreen = false;
|
RecycleScreen = false;
|
||||||
|
EntryInfoViewModel = entryInfoViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LayoutDescriptionViewModel LayoutDescriptionViewModel { get; }
|
public override RoutableScreen DefaultScreen => _layoutDescriptionViewModel;
|
||||||
|
public EntryInfoViewModel EntryInfoViewModel { get; }
|
||||||
|
|
||||||
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@ -47,14 +47,18 @@ public partial class LayoutDetailsViewModel : RoutableHostScreen<RoutableScreen,
|
|||||||
|
|
||||||
private async Task GetEntry(long entryId, CancellationToken cancellationToken)
|
private async Task GetEntry(long entryId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
Task grace = Task.Delay(300, cancellationToken);
|
||||||
IOperationResult<IGetEntryByIdResult> result = await _client.GetEntryById.ExecuteAsync(entryId, cancellationToken);
|
IOperationResult<IGetEntryByIdResult> result = await _client.GetEntryById.ExecuteAsync(entryId, cancellationToken);
|
||||||
if (result.IsErrorResult())
|
if (result.IsErrorResult())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Let the UI settle to avoid lag when deep linking
|
||||||
|
await grace;
|
||||||
|
|
||||||
Entry = result.Data?.Entry;
|
Entry = result.Data?.Entry;
|
||||||
EntryInfoViewModel = Entry != null ? _getEntryInfoViewModel(Entry) : null;
|
EntryInfoViewModel.SetEntry(Entry);
|
||||||
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
||||||
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
||||||
LayoutDescriptionViewModel.Entry = Entry;
|
_layoutDescriptionViewModel.Entry = Entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,7 +13,8 @@ public partial class LayoutListView : ReactiveUserControl<LayoutListViewModel>
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
||||||
.Subscribe(screen => RouterFrame.NavigateFromObject(screen ?? ViewModel?.EntryListViewModel))
|
.WhereNotNull()
|
||||||
|
.Subscribe(screen => RouterFrame.NavigateFromObject(screen))
|
||||||
.DisposeWith(d));
|
.DisposeWith(d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,11 +6,12 @@ namespace Artemis.UI.Screens.Workshop.Layout;
|
|||||||
|
|
||||||
public class LayoutListViewModel : RoutableHostScreen<RoutableScreen>
|
public class LayoutListViewModel : RoutableHostScreen<RoutableScreen>
|
||||||
{
|
{
|
||||||
public EntryListViewModel EntryListViewModel { get; }
|
private readonly EntryListViewModel _entryListViewModel;
|
||||||
|
public override RoutableScreen DefaultScreen => _entryListViewModel;
|
||||||
|
|
||||||
public LayoutListViewModel(EntryListViewModel entryListViewModel)
|
public LayoutListViewModel(EntryListViewModel entryListViewModel)
|
||||||
{
|
{
|
||||||
EntryListViewModel = entryListViewModel;
|
_entryListViewModel = entryListViewModel;
|
||||||
EntryListViewModel.EntryType = EntryType.Layout;
|
_entryListViewModel.EntryType = EntryType.Layout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,7 +13,12 @@
|
|||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid ColumnDefinitions="300,*" RowDefinitions="*, Auto">
|
<Panel>
|
||||||
|
<ProgressBar HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
IsVisible="{CompiledBinding Entry, Converter={x:Static ObjectConverters.IsNull}}"
|
||||||
|
IsIndeterminate="True" />
|
||||||
|
<Grid ColumnDefinitions="300,*" RowDefinitions="*, Auto" IsVisible="{CompiledBinding Entry, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
<StackPanel Grid.Column="0" Grid.Row="0" Spacing="10" Margin="0 0 10 0">
|
<StackPanel Grid.Column="0" Grid.Row="0" Spacing="10" Margin="0 0 10 0">
|
||||||
<Border Classes="card" VerticalAlignment="Top">
|
<Border Classes="card" VerticalAlignment="Top">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
@ -76,5 +81,5 @@
|
|||||||
</controls:Frame.NavigationPageFactory>
|
</controls:Frame.NavigationPageFactory>
|
||||||
</controls:Frame>
|
</controls:Frame>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Panel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -11,7 +11,8 @@ public partial class SubmissionManagementView : ReactiveUserControl<SubmissionMa
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
||||||
.Subscribe(screen => RouterFrame.NavigateFromObject(screen ?? ViewModel?.DetailsViewModel))
|
.WhereNotNull()
|
||||||
|
.Subscribe(screen => RouterFrame.NavigateFromObject(screen))
|
||||||
.DisposeWith(d));
|
.DisposeWith(d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22,6 +22,7 @@ public partial class SubmissionManagementViewModel : RoutableHostScreen<Routable
|
|||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private readonly IRouter _router;
|
private readonly IRouter _router;
|
||||||
private readonly IWorkshopService _workshopService;
|
private readonly IWorkshopService _workshopService;
|
||||||
|
private readonly SubmissionDetailsViewModel _detailsViewModel;
|
||||||
|
|
||||||
[Notify] private IGetSubmittedEntryById_Entry? _entry;
|
[Notify] private IGetSubmittedEntryById_Entry? _entry;
|
||||||
[Notify] private List<IGetSubmittedEntryById_Entry_Releases>? _releases;
|
[Notify] private List<IGetSubmittedEntryById_Entry_Releases>? _releases;
|
||||||
@ -29,7 +30,7 @@ public partial class SubmissionManagementViewModel : RoutableHostScreen<Routable
|
|||||||
|
|
||||||
public SubmissionManagementViewModel(IWorkshopClient client, IRouter router, IWindowService windowService, IWorkshopService workshopService, SubmissionDetailsViewModel detailsViewModel)
|
public SubmissionManagementViewModel(IWorkshopClient client, IRouter router, IWindowService windowService, IWorkshopService workshopService, SubmissionDetailsViewModel detailsViewModel)
|
||||||
{
|
{
|
||||||
DetailsViewModel = detailsViewModel;
|
_detailsViewModel = detailsViewModel;
|
||||||
_client = client;
|
_client = client;
|
||||||
_router = router;
|
_router = router;
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
@ -39,12 +40,12 @@ public partial class SubmissionManagementViewModel : RoutableHostScreen<Routable
|
|||||||
{
|
{
|
||||||
this.WhenAnyValue(vm => vm.SelectedRelease)
|
this.WhenAnyValue(vm => vm.SelectedRelease)
|
||||||
.WhereNotNull()
|
.WhereNotNull()
|
||||||
.Subscribe(r => _router.Navigate($"/releases/{r.Id}"))
|
.Subscribe(r => _router.Navigate($"workshop/library/submissions/{Entry?.Id}/releases/{r.Id}"))
|
||||||
.DisposeWith(d);
|
.DisposeWith(d);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubmissionDetailsViewModel DetailsViewModel { get; }
|
public override RoutableScreen DefaultScreen => _detailsViewModel;
|
||||||
|
|
||||||
public async Task ViewWorkshopPage()
|
public async Task ViewWorkshopPage()
|
||||||
{
|
{
|
||||||
@ -87,11 +88,11 @@ public partial class SubmissionManagementViewModel : RoutableHostScreen<Routable
|
|||||||
Entry = result.Data?.Entry;
|
Entry = result.Data?.Entry;
|
||||||
Releases = Entry?.Releases.OrderByDescending(r => r.CreatedAt).ToList();
|
Releases = Entry?.Releases.OrderByDescending(r => r.CreatedAt).ToList();
|
||||||
|
|
||||||
await DetailsViewModel.SetEntry(Entry, cancellationToken);
|
await _detailsViewModel.SetEntry(Entry, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnClosing(NavigationArguments args)
|
public override async Task OnClosing(NavigationArguments args)
|
||||||
{
|
{
|
||||||
await DetailsViewModel.OnClosing(args);
|
await _detailsViewModel.OnClosing(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,7 +2,6 @@
|
|||||||
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:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight"
|
|
||||||
xmlns:plugins="clr-namespace:Artemis.UI.Screens.Workshop.Plugins"
|
xmlns:plugins="clr-namespace:Artemis.UI.Screens.Workshop.Plugins"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
@ -17,7 +16,16 @@
|
|||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Entry.PluginInfo, Converter={x:Static ObjectConverters.IsNotNull}}">
|
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Entry.PluginInfo, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
<StackPanel>
|
<Panel>
|
||||||
|
<StackPanel IsVisible="{CompiledBinding Entry, Converter={x:Static ObjectConverters.IsNull}}">
|
||||||
|
<Border Width="110" Classes="skeleton-text"></Border>
|
||||||
|
<Border Width="35" Classes="skeleton-text"></Border>
|
||||||
|
|
||||||
|
<Border Margin="0 16 0 3" Width="130" Classes="skeleton-text"></Border>
|
||||||
|
<Border Width="60" Classes="skeleton-text"></Border>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel IsVisible="{CompiledBinding Entry, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
<TextBlock>Admin required</TextBlock>
|
<TextBlock>Admin required</TextBlock>
|
||||||
<TextBlock Text="Yes" IsVisible="{CompiledBinding Entry.PluginInfo.RequiresAdmin}" />
|
<TextBlock Text="Yes" IsVisible="{CompiledBinding Entry.PluginInfo.RequiresAdmin}" />
|
||||||
<TextBlock Text="No" IsVisible="{CompiledBinding !Entry.PluginInfo.RequiresAdmin}" />
|
<TextBlock Text="No" IsVisible="{CompiledBinding !Entry.PluginInfo.RequiresAdmin}" />
|
||||||
@ -29,9 +37,11 @@
|
|||||||
<avalonia:MaterialIcon Kind="Apple" IsVisible="{CompiledBinding Entry.PluginInfo.SupportsOSX}" />
|
<avalonia:MaterialIcon Kind="Apple" IsVisible="{CompiledBinding Entry.PluginInfo.SupportsOSX}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Entry.Releases.Count}">
|
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Entry.Releases.Count, FallbackValue=False}">
|
||||||
<ContentControl Content="{CompiledBinding EntryReleasesViewModel}" />
|
<ContentControl Content="{CompiledBinding EntryReleasesViewModel}" />
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@ -44,6 +54,6 @@
|
|||||||
</controls:Frame>
|
</controls:Frame>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
<ContentControl Grid.Row="1" Grid.Column="2" IsVisible="{CompiledBinding Entry.Images.Count}" Content="{CompiledBinding EntryImagesViewModel}" />
|
<ContentControl Grid.Row="1" Grid.Column="2" IsVisible="{CompiledBinding Entry.Images.Count, FallbackValue=False}" Content="{CompiledBinding EntryImagesViewModel}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -11,7 +11,8 @@ public partial class PluginDetailsView : ReactiveUserControl<PluginDetailsViewMo
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
||||||
.Subscribe(screen => RouterFrame.NavigateFromObject(screen ?? ViewModel?.PluginDescriptionViewModel))
|
.WhereNotNull()
|
||||||
|
.Subscribe(screen => RouterFrame.NavigateFromObject(screen))
|
||||||
.DisposeWith(d));
|
.DisposeWith(d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16,31 +16,31 @@ namespace Artemis.UI.Screens.Workshop.Plugins;
|
|||||||
public partial class PluginDetailsViewModel : RoutableHostScreen<RoutableScreen, WorkshopDetailParameters>
|
public partial class PluginDetailsViewModel : RoutableHostScreen<RoutableScreen, WorkshopDetailParameters>
|
||||||
{
|
{
|
||||||
private readonly IWorkshopClient _client;
|
private readonly IWorkshopClient _client;
|
||||||
private readonly Func<IEntryDetails, EntryInfoViewModel> _getEntryInfoViewModel;
|
private readonly PluginDescriptionViewModel _pluginDescriptionViewModel;
|
||||||
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
||||||
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
|
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
|
||||||
[Notify] private IGetPluginEntryById_Entry? _entry;
|
[Notify] private IGetPluginEntryById_Entry? _entry;
|
||||||
[Notify] private EntryInfoViewModel? _entryInfoViewModel;
|
|
||||||
[Notify] private EntryReleasesViewModel? _entryReleasesViewModel;
|
[Notify] private EntryReleasesViewModel? _entryReleasesViewModel;
|
||||||
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
|
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
|
||||||
[Notify] private ReadOnlyObservableCollection<EntryListItemViewModel>? _dependants;
|
[Notify] private ReadOnlyObservableCollection<EntryListItemViewModel>? _dependants;
|
||||||
|
|
||||||
public PluginDetailsViewModel(IWorkshopClient client,
|
public PluginDetailsViewModel(IWorkshopClient client,
|
||||||
PluginDescriptionViewModel pluginDescriptionViewModel,
|
PluginDescriptionViewModel pluginDescriptionViewModel,
|
||||||
Func<IEntryDetails, EntryInfoViewModel> getEntryInfoViewModel,
|
EntryInfoViewModel entryInfoViewModel,
|
||||||
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
|
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
|
||||||
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel)
|
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_getEntryInfoViewModel = getEntryInfoViewModel;
|
_pluginDescriptionViewModel = pluginDescriptionViewModel;
|
||||||
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
||||||
_getEntryImagesViewModel = getEntryImagesViewModel;
|
_getEntryImagesViewModel = getEntryImagesViewModel;
|
||||||
|
|
||||||
PluginDescriptionViewModel = pluginDescriptionViewModel;
|
EntryInfoViewModel = entryInfoViewModel;
|
||||||
RecycleScreen = false;
|
RecycleScreen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginDescriptionViewModel PluginDescriptionViewModel { get; }
|
public override RoutableScreen DefaultScreen => _pluginDescriptionViewModel;
|
||||||
|
public EntryInfoViewModel EntryInfoViewModel { get; }
|
||||||
|
|
||||||
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@ -50,15 +50,19 @@ public partial class PluginDetailsViewModel : RoutableHostScreen<RoutableScreen,
|
|||||||
|
|
||||||
private async Task GetEntry(long entryId, CancellationToken cancellationToken)
|
private async Task GetEntry(long entryId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
Task grace = Task.Delay(300, cancellationToken);
|
||||||
IOperationResult<IGetPluginEntryByIdResult> result = await _client.GetPluginEntryById.ExecuteAsync(entryId, cancellationToken);
|
IOperationResult<IGetPluginEntryByIdResult> result = await _client.GetPluginEntryById.ExecuteAsync(entryId, cancellationToken);
|
||||||
if (result.IsErrorResult())
|
if (result.IsErrorResult())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Let the UI settle to avoid lag when deep linking
|
||||||
|
await grace;
|
||||||
|
|
||||||
Entry = result.Data?.Entry;
|
Entry = result.Data?.Entry;
|
||||||
EntryInfoViewModel = Entry != null ? _getEntryInfoViewModel(Entry) : null;
|
EntryInfoViewModel.SetEntry(Entry);
|
||||||
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
||||||
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
||||||
|
|
||||||
await PluginDescriptionViewModel.SetEntry(Entry, cancellationToken);
|
await _pluginDescriptionViewModel.SetEntry(Entry, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11,7 +11,8 @@ public partial class PluginListView : ReactiveUserControl<PluginListViewModel>
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
||||||
.Subscribe(screen => RouterFrame.NavigateFromObject(screen ?? ViewModel?.EntryListViewModel))
|
.WhereNotNull()
|
||||||
|
.Subscribe(screen => RouterFrame.NavigateFromObject(screen))
|
||||||
.DisposeWith(d));
|
.DisposeWith(d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,11 +6,12 @@ namespace Artemis.UI.Screens.Workshop.Plugins;
|
|||||||
|
|
||||||
public class PluginListViewModel : RoutableHostScreen<RoutableScreen>
|
public class PluginListViewModel : RoutableHostScreen<RoutableScreen>
|
||||||
{
|
{
|
||||||
public EntryListViewModel EntryListViewModel { get; }
|
private readonly EntryListViewModel _entryListViewModel;
|
||||||
|
public override RoutableScreen DefaultScreen => _entryListViewModel;
|
||||||
|
|
||||||
public PluginListViewModel(EntryListViewModel entryListViewModel)
|
public PluginListViewModel(EntryListViewModel entryListViewModel)
|
||||||
{
|
{
|
||||||
EntryListViewModel = entryListViewModel;
|
_entryListViewModel = entryListViewModel;
|
||||||
EntryListViewModel.EntryType = EntryType.Plugin;
|
_entryListViewModel.EntryType = EntryType.Plugin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,7 +3,6 @@
|
|||||||
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"
|
xmlns:profile="clr-namespace:Artemis.UI.Screens.Workshop.Profile"
|
||||||
xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight"
|
|
||||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:ui="clr-namespace:Artemis.UI"
|
xmlns:ui="clr-namespace:Artemis.UI"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800"
|
||||||
@ -14,7 +13,7 @@
|
|||||||
<Border Classes="card" VerticalAlignment="Top">
|
<Border Classes="card" VerticalAlignment="Top">
|
||||||
<ContentControl Content="{CompiledBinding EntryInfoViewModel}" />
|
<ContentControl Content="{CompiledBinding EntryInfoViewModel}" />
|
||||||
</Border>
|
</Border>
|
||||||
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Entry.Releases.Count}">
|
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Entry.Releases.Count, FallbackValue=False}">
|
||||||
<ContentControl Content="{CompiledBinding EntryReleasesViewModel}" />
|
<ContentControl Content="{CompiledBinding EntryReleasesViewModel}" />
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@ -27,6 +26,6 @@
|
|||||||
</controls:Frame>
|
</controls:Frame>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
<ContentControl Grid.Row="1" Grid.Column="2" IsVisible="{CompiledBinding Entry.Images.Count}" Content="{CompiledBinding EntryImagesViewModel}" />
|
<ContentControl Grid.Row="1" Grid.Column="2" IsVisible="{CompiledBinding Entry.Images.Count, FallbackValue=False}" Content="{CompiledBinding EntryImagesViewModel}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -11,7 +11,8 @@ public partial class ProfileDetailsView : ReactiveUserControl<ProfileDetailsView
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
||||||
.Subscribe(screen => RouterFrame.NavigateFromObject(screen ?? ViewModel?.ProfileDescriptionViewModel))
|
.WhereNotNull()
|
||||||
|
.Subscribe(screen => RouterFrame.NavigateFromObject(screen))
|
||||||
.DisposeWith(d));
|
.DisposeWith(d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17,31 +17,31 @@ namespace Artemis.UI.Screens.Workshop.Profile;
|
|||||||
public partial class ProfileDetailsViewModel : RoutableHostScreen<RoutableScreen, WorkshopDetailParameters>
|
public partial class ProfileDetailsViewModel : RoutableHostScreen<RoutableScreen, WorkshopDetailParameters>
|
||||||
{
|
{
|
||||||
private readonly IWorkshopClient _client;
|
private readonly IWorkshopClient _client;
|
||||||
private readonly Func<IEntryDetails, EntryInfoViewModel> _getEntryInfoViewModel;
|
private readonly ProfileDescriptionViewModel _profileDescriptionViewModel;
|
||||||
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
||||||
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
|
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
|
||||||
|
|
||||||
[Notify] private IEntryDetails? _entry;
|
[Notify] private IEntryDetails? _entry;
|
||||||
[Notify] private EntryInfoViewModel? _entryInfoViewModel;
|
|
||||||
[Notify] private EntryReleasesViewModel? _entryReleasesViewModel;
|
[Notify] private EntryReleasesViewModel? _entryReleasesViewModel;
|
||||||
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
|
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
|
||||||
|
|
||||||
public ProfileDetailsViewModel(IWorkshopClient client,
|
public ProfileDetailsViewModel(IWorkshopClient client,
|
||||||
ProfileDescriptionViewModel profileDescriptionViewModel,
|
ProfileDescriptionViewModel profileDescriptionViewModel,
|
||||||
Func<IEntryDetails, EntryInfoViewModel> getEntryInfoViewModel,
|
EntryInfoViewModel entryInfoViewModel,
|
||||||
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
|
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
|
||||||
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel)
|
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_getEntryInfoViewModel = getEntryInfoViewModel;
|
_profileDescriptionViewModel = profileDescriptionViewModel;
|
||||||
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
||||||
_getEntryImagesViewModel = getEntryImagesViewModel;
|
_getEntryImagesViewModel = getEntryImagesViewModel;
|
||||||
|
|
||||||
ProfileDescriptionViewModel = profileDescriptionViewModel;
|
EntryInfoViewModel = entryInfoViewModel;
|
||||||
RecycleScreen = false;
|
RecycleScreen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileDescriptionViewModel ProfileDescriptionViewModel { get; }
|
public override RoutableScreen DefaultScreen => _profileDescriptionViewModel;
|
||||||
|
public EntryInfoViewModel EntryInfoViewModel { get; }
|
||||||
|
|
||||||
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@ -51,15 +51,19 @@ public partial class ProfileDetailsViewModel : RoutableHostScreen<RoutableScreen
|
|||||||
|
|
||||||
private async Task GetEntry(long entryId, CancellationToken cancellationToken)
|
private async Task GetEntry(long entryId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
Task grace = Task.Delay(300, cancellationToken);
|
||||||
IOperationResult<IGetEntryByIdResult> result = await _client.GetEntryById.ExecuteAsync(entryId, cancellationToken);
|
IOperationResult<IGetEntryByIdResult> result = await _client.GetEntryById.ExecuteAsync(entryId, cancellationToken);
|
||||||
if (result.IsErrorResult())
|
if (result.IsErrorResult())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Let the UI settle to avoid lag when deep linking
|
||||||
|
await grace;
|
||||||
|
|
||||||
Entry = result.Data?.Entry;
|
Entry = result.Data?.Entry;
|
||||||
EntryInfoViewModel = Entry != null ? _getEntryInfoViewModel(Entry) : null;
|
EntryInfoViewModel.SetEntry(Entry);
|
||||||
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
||||||
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
||||||
|
|
||||||
await ProfileDescriptionViewModel.SetEntry(Entry, cancellationToken);
|
await _profileDescriptionViewModel.SetEntry(Entry, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11,7 +11,8 @@ public partial class ProfileListView : ReactiveUserControl<ProfileListViewModel>
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen)
|
||||||
.Subscribe(screen => RouterFrame.NavigateFromObject(screen ?? ViewModel?.EntryListViewModel))
|
.WhereNotNull()
|
||||||
|
.Subscribe(screen => RouterFrame.NavigateFromObject(screen))
|
||||||
.DisposeWith(d));
|
.DisposeWith(d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,11 +6,12 @@ namespace Artemis.UI.Screens.Workshop.Profile;
|
|||||||
|
|
||||||
public class ProfileListViewModel : RoutableHostScreen<RoutableScreen>
|
public class ProfileListViewModel : RoutableHostScreen<RoutableScreen>
|
||||||
{
|
{
|
||||||
public EntryListViewModel EntryListViewModel { get; }
|
private readonly EntryListViewModel _entryListViewModel;
|
||||||
|
public override RoutableScreen DefaultScreen => _entryListViewModel;
|
||||||
|
|
||||||
public ProfileListViewModel(EntryListViewModel entryListViewModel)
|
public ProfileListViewModel(EntryListViewModel entryListViewModel)
|
||||||
{
|
{
|
||||||
EntryListViewModel = entryListViewModel;
|
_entryListViewModel = entryListViewModel;
|
||||||
EntryListViewModel.EntryType = EntryType.Profile;
|
_entryListViewModel.EntryType = EntryType.Profile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
namespace Artemis.WebClient.Workshop.Extensions;
|
||||||
|
|
||||||
|
public static class EntryExtensions
|
||||||
|
{
|
||||||
|
public static string GetEntryPath(this IEntryDetails entry)
|
||||||
|
{
|
||||||
|
return $"workshop/entries/{entry.EntryType.ToString().ToLower()}s/details/{entry.Id}";
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user