WIP modlist contents viewer

This commit is contained in:
Timothy Baldridge 2021-04-28 05:57:49 -06:00
parent 7e29706b38
commit 5051e800b4
10 changed files with 279 additions and 10 deletions

View File

@ -8,12 +8,14 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using K4os.Compression.LZ4.Internal;
using Newtonsoft.Json;
using Org.BouncyCastle.Crypto.Agreement.Srp;
using Wabbajack.Common;
using Wabbajack.Common.Exceptions;
using Wabbajack.Common.Serialization.Json;
using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.LibCefHelpers;
using Wabbajack.Lib.ModListRegistry;
namespace Wabbajack.Lib
{
@ -80,6 +82,40 @@ using Wabbajack.Lib.Downloaders;
}
}
[JsonName("DetailedStatus")]
public class DetailedStatus
{
public string Name { get; set; } = "";
public DateTime Checked { get; set; } = DateTime.UtcNow;
public List<DetailedStatusItem> Archives { get; set; } = new();
public DownloadMetadata DownloadMetaData { get; set; } = new();
public bool HasFailures { get; set; }
public string MachineName { get; set; } = "";
}
[JsonName("DetailedStatusItem")]
public class DetailedStatusItem
{
public bool IsFailing { get; set; }
public Archive? Archive { get; set; }
public string Name => string.IsNullOrWhiteSpace(Archive!.Name) ? Archive.State.PrimaryKeyString : Archive.Name;
public string? Url => Archive?.State.GetManifestURL(Archive!);
[JsonIgnore]
public bool HasUrl => Url != null;
public ArchiveStatus ArchiveStatus { get; set; }
}
public enum ArchiveStatus
{
Valid,
InValid,
Updating,
Updated,
Mirrored
}
public class ClientAPI
{
public static async Task<Wabbajack.Lib.Http.Client> GetClient()
@ -298,5 +334,14 @@ using Wabbajack.Lib.Downloaders;
$"{Consts.WabbajackBuildServerUri}game_files");
return results;
}
public static async Task<DetailedStatus> GetDetailedStatus(string machineURL)
{
var client = await GetClient();
var results =
await client.GetJsonAsync<DetailedStatus>(
$"{Consts.WabbajackBuildServerUri}lists/status/{machineURL}.json");
return results;
}
}
}

View File

@ -141,6 +141,11 @@ Global
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|Any CPU.ActiveCfg = Release|x64
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.ActiveCfg = Release|x64
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.Build.0 = Release|x64
{44E30B97-D4A8-40A6-81D5-5CAB1F3D45CB}.Debug|Any CPU.ActiveCfg = Debug|x64
{44E30B97-D4A8-40A6-81D5-5CAB1F3D45CB}.Debug|x64.ActiveCfg = Debug|x64
{44E30B97-D4A8-40A6-81D5-5CAB1F3D45CB}.Debug|x64.Build.0 = Debug|x64
{44E30B97-D4A8-40A6-81D5-5CAB1F3D45CB}.Release|Any CPU.ActiveCfg = Release|x64
{44E30B97-D4A8-40A6-81D5-5CAB1F3D45CB}.Release|x64.ActiveCfg = Release|x64
{3E11B700-8405-433D-BF47-6C356087A7C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E11B700-8405-433D-BF47-6C356087A7C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E11B700-8405-433D-BF47-6C356087A7C2}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -157,7 +162,6 @@ Global
{9DEC8DC8-B6E0-469B-9571-C4BAC0776D07}.Release|Any CPU.Build.0 = Release|Any CPU
{9DEC8DC8-B6E0-469B-9571-C4BAC0776D07}.Release|x64.ActiveCfg = Release|Any CPU
{9DEC8DC8-B6E0-469B-9571-C4BAC0776D07}.Release|x64.Build.0 = Release|Any CPU
{44E30B97-D4A8-40A6-81D5-5CAB1F3D45CB}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -39,6 +39,8 @@ namespace Wabbajack
public ICommand OpenWebsiteCommand { get; }
public ICommand ExecuteCommand { get; }
public ICommand ModListContentsCommend { get; }
private readonly ObservableAsPropertyHelper<bool> _Exists;
public bool Exists => _Exists.Value;
@ -90,6 +92,15 @@ namespace Wabbajack
IsBroken = metadata.ValidationSummary.HasFailures || metadata.ForceDown;
//https://www.wabbajack.org/#/modlists/info?machineURL=eldersouls
OpenWebsiteCommand = ReactiveCommand.Create(() => Utils.OpenWebsite(new Uri($"https://www.wabbajack.org/#/modlists/info?machineURL={Metadata.Links.MachineURL}")));
ModListContentsCommend = ReactiveCommand.Create(async () =>
{
_parent.MWVM.ModListContentsVM.Value.Name = metadata.Title;
var status = await ClientAPI.GetDetailedStatus(metadata.Links.MachineURL);
var coll = _parent.MWVM.ModListContentsVM.Value.Status;
coll.Clear();
coll.AddRange(status.Archives);
_parent.MWVM.NavigateTo(_parent.MWVM.ModListContentsVM.Value);
});
ExecuteCommand = ReactiveCommand.CreateFromObservable<Unit, Unit>(
canExecute: this.WhenAny(x => x.IsBroken).Select(x => !x),
execute: (unit) =>
@ -177,6 +188,8 @@ namespace Wabbajack
.ToGuiProperty(this, nameof(LoadingImage));
}
private async Task<bool> Download()
{
ProgressPercent = Percent.Zero;

View File

@ -41,6 +41,7 @@ namespace Wabbajack
public readonly Lazy<SettingsVM> SettingsPane;
public readonly Lazy<ModListGalleryVM> Gallery;
public readonly ModeSelectionVM ModeSelectionVM;
public readonly Lazy<ModListContentsVM> ModListContentsVM;
public readonly UserInterventionHandlers UserInterventionHandlers;
public ICommand CopyVersionCommand { get; }
@ -62,6 +63,7 @@ namespace Wabbajack
SettingsPane = new Lazy<SettingsVM>(() => new SettingsVM(this));
Gallery = new Lazy<ModListGalleryVM>(() => new ModListGalleryVM(this));
ModeSelectionVM = new ModeSelectionVM(this);
ModListContentsVM = new Lazy<ModListContentsVM>(() => new ModListContentsVM(this));
UserInterventionHandlers = new UserInterventionHandlers(this);
// Set up logging

View File

@ -0,0 +1,72 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text.RegularExpressions;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Lib;
using ReactiveUI;
using DynamicData;
using DynamicData.Binding;
using Wabbajack.Common;
namespace Wabbajack
{
public class ModListContentsVM : ViewModel
{
private MainWindowVM _mwvm;
[Reactive]
public string Name { get; set; }
[Reactive]
public ObservableCollection<DetailedStatusItem> Status { get; set; }
[Reactive]
public string SearchString { get; set; }
private readonly ReadOnlyObservableCollection<ModListArchive> _archives;
public ReadOnlyObservableCollection<ModListArchive> Archives => _archives;
public ModListContentsVM(MainWindowVM mwvm)
{
_mwvm = mwvm;
Status = new ObservableCollectionExtended<DetailedStatusItem>();
Regex nameMatcher = new Regex(@"(?<=\.)[^\.]+(?=\+State)");
string TransformClassName(Archive a)
{
var cname = a.State.GetType().FullName;
if (cname == null) return null;
var match = nameMatcher.Match(cname);
return match.Success ? match.ToString() : null;
}
this.Status
.ToObservableChangeSet()
.Transform(a => new ModListArchive
{
Name = a.Name,
Size = a.Archive?.Size.ToFileSizeString(),
Url = a.Url ?? "",
Downloader = TransformClassName(a.Archive) ?? "Unknown",
Hash = a.Archive!.Hash.ToBase64()
})
.Bind(out _archives)
.Subscribe()
.DisposeWith(CompositeDisposable);
}
}
public class ModListArchive
{
public string Name { get; set; }
public string Size { get; set; }
public string Url { get; set; }
public string Downloader { get; set; }
public string Hash { get; set; }
}
}

View File

@ -40,6 +40,9 @@
<DataTemplate DataType="{x:Type local:SettingsVM}">
<local:SettingsView ViewModel="{Binding}" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ModListContentsVM}">
<local:ModListContentsView ViewModel="{Binding}" />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>

View File

@ -0,0 +1,66 @@
<rxui:ReactiveUserControl
x:Class="Wabbajack.ModListContentsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wabbajack"
xmlns:rxui="http://reactiveui.net"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
x:TypeArguments="local:ModListContentsVM"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="47"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<local:TopProgressView Grid.Row="0" Grid.RowSpan="2"
x:Name="ModListTitle"
ShadowMargin="False" />
<WrapPanel Grid.Row="0"
Height="25"
Margin="5,5,5,10"
HorizontalAlignment="Right"
Orientation="Horizontal">
<TextBlock
Margin="0,0,5,0"
VerticalAlignment="Center"
Foreground="{StaticResource ForegroundBrush}"
Text="Search" />
<TextBox
x:Name="SearchBox"
Width="300"
VerticalContentAlignment="Center" />
<Button
x:Name="ClearFiltersButton"
Margin="0,0,10,0"
Style="{StaticResource IconBareButtonStyle}"
ToolTip="Clear All Filters">
<iconPacks:Material Kind="FilterRemove" />
</Button>
</WrapPanel>
<Button Grid.Row="0"
x:Name="BackButton"
Width="30"
Height="30"
Margin="7,5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Style="{StaticResource IconCircleButtonStyle}"
ToolTip="Back to main menu">
<iconPacks:PackIconMaterial Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Kind="ArrowLeft" />
</Button>
<DataGrid Grid.Row="1" x:Name="ArchiveGrid" AutoGenerateColumns="False" AlternatingRowBackground="#131313" FontSize="14">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"></DataGridTextColumn>
<DataGridTextColumn Header="Downloader" Binding="{Binding Downloader}"></DataGridTextColumn>
<DataGridTextColumn Header="Size" Binding="{Binding Size}"></DataGridTextColumn>
<DataGridTextColumn Header="Hash" Binding="{Binding Hash}"></DataGridTextColumn>
<DataGridHyperlinkColumn Header="Link" Binding="{Binding Url}"></DataGridHyperlinkColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</rxui:ReactiveUserControl>

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows.Controls;
using System.Windows.Xps;
using ReactiveUI;
using DynamicData;
using DynamicData.Binding;
using ReactiveUI.Fody.Helpers;
namespace Wabbajack
{
public partial class ModListContentsView
{
public ModListContentsView()
{
InitializeComponent();
this.WhenActivated(disposable =>
{
/*
var queryText = this
.WhenAny(x => x.SearchBox)
.Select(t => t.Text)
.StartWith("")
.Select<string, Func<ModListArchive, bool>>(s => (ModListArchive ar) =>
string.IsNullOrEmpty(s) ||
ar.Name.ContainsCaseInsensitive(s) ||
ar.Downloader.ContainsCaseInsensitive(s) ||
ar.Hash.ContainsCaseInsensitive(s) ||
ar.Size.ContainsCaseInsensitive(s) ||
ar.Url.ContainsCaseInsensitive(s));
*/
this.ArchiveGrid.ItemsSource = this.ViewModel.Archives;
this.WhenAny(x => x.ViewModel.Name)
.BindToStrict(this, x => x.ModListTitle.Title)
.DisposeWith(disposable);
/*this.WhenAny(x => x.ViewModel.Archives)
.BindToStrict(this, x => x.ArchiveGrid.ItemsSource)
.DisposeWith(disposable);*/
});
}
}
}

View File

@ -262,7 +262,7 @@
FontSize="14"
TextWrapping="Wrap" />
</ScrollViewer>
<ItemsControl Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding ModListTagList}">
<ItemsControl Grid.Row="2" ItemsSource="{Binding ModListTagList}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
@ -285,29 +285,42 @@
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid Grid.Row="1" Grid.Column="1">
<Grid Grid.Row="1" Grid.Column="1" Grid.RowSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="0"
x:Name="OpenWebsiteButton"
Width="40"
Height="40"
Margin="5,0"
VerticalAlignment="Bottom"
Style="{StaticResource IconBareButtonStyle}">
x:Name="OpenWebsiteButton"
Width="40"
Height="40"
Margin="5,0"
VerticalAlignment="Center"
Style="{StaticResource IconBareButtonStyle}">
<iconPacks:Material
Width="20"
Height="20"
Kind="Web" />
</Button>
<Button Grid.Row="1"
x:Name="ModListContentsButton"
Width="40"
Height="40"
Margin="5,0"
VerticalAlignment="Center"
Style="{StaticResource IconBareButtonStyle}">
<iconPacks:Material
Width="20"
Height="20"
Kind="TableSearch" />
</Button>
<Button Grid.Row="2"
x:Name="ExecuteButton"
Width="40"
Height="40"
Margin="5,0"
VerticalAlignment="Top">
VerticalAlignment="Center">
<Button.Style>
<Style BasedOn="{StaticResource IconBareButtonStyle}" TargetType="Button">
<Setter Property="Content">
@ -354,6 +367,7 @@
</Style>
</Button.Style>
</Button>
</Grid>
</Grid>
</Border>

View File

@ -59,6 +59,9 @@ namespace Wabbajack
this.WhenAny(x => x.ViewModel.OpenWebsiteCommand)
.BindToStrict(this, x => x.OpenWebsiteButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ModListContentsCommend)
.BindToStrict(this, x => x.ModListContentsButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ExecuteCommand)
.BindToStrict(this, x => x.ExecuteButton.Command)
.DisposeWith(dispose);