Rework how we download/install curated lists

This commit is contained in:
Timothy Baldridge 2019-11-28 22:52:33 -07:00
parent edcf75c28c
commit 70fead926f
6 changed files with 194 additions and 69 deletions

View File

@ -106,7 +106,7 @@ namespace Wabbajack.Lib
} }
Utils.Log("Exporting ModList metadata"); Utils.Log("Exporting ModList metadata");
var metadata = new ModlistMetadata.DownloadMetadata var metadata = new DownloadMetadata
{ {
Size = File.GetSize(ModListOutputFile), Size = File.GetSize(ModListOutputFile),
Hash = ModListOutputFile.FileHash(), Hash = ModListOutputFile.FileHash(),

View File

@ -30,6 +30,9 @@ namespace Wabbajack.Lib.ModListRegistry
[JsonProperty("links")] [JsonProperty("links")]
public LinksObject Links { get; set; } = new LinksObject(); public LinksObject Links { get; set; } = new LinksObject();
[JsonProperty("download_metadata")]
public DownloadMetadata DownloadMetadata { get; set; }
public class LinksObject public class LinksObject
{ {
[JsonProperty("image")] [JsonProperty("image")]
@ -43,26 +46,13 @@ namespace Wabbajack.Lib.ModListRegistry
[JsonProperty("download")] [JsonProperty("download")]
public string Download { get; set; } public string Download { get; set; }
[JsonProperty("download_metadata")]
public DownloadMetadata DownloadMetadata { get; set; }
[JsonProperty("machineURL")] [JsonProperty("machineURL")]
public string MachineURL { get; set; } public string MachineURL { get; set; }
} }
public class DownloadMetadata
{
public string Hash { get; set; }
public long Size { get; set; }
public long NumberOfArchives { get; set; }
public long SizeOfArchives { get; set; }
public long NumberOfInstalledFiles { get; set; }
public long SizeOfInstalledFiles { get; set; }
}
public static List<ModlistMetadata> LoadFromGithub() public static List<ModlistMetadata> LoadFromGithub()
@ -76,12 +66,24 @@ namespace Wabbajack.Lib.ModListRegistry
public bool NeedsDownload(string modlistPath) public bool NeedsDownload(string modlistPath)
{ {
if (!File.Exists(modlistPath)) return true; if (!File.Exists(modlistPath)) return true;
if (Links.DownloadMetadata?.Hash == null) if (DownloadMetadata?.Hash == null)
{ {
return true; return true;
} }
return Links.DownloadMetadata.Hash != modlistPath.FileHash(); return DownloadMetadata.Hash != modlistPath.FileHashCached();
} }
} }
public class DownloadMetadata
{
public string Hash { get; set; }
public long Size { get; set; }
public long NumberOfArchives { get; set; }
public long SizeOfArchives { get; set; }
public long NumberOfInstalledFiles { get; set; }
public long SizeOfInstalledFiles { get; set; }
}
} }

View File

@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Alphaleonis.Win32.Filesystem;
using ReactiveUI;
using Wabbajack.Common;
using Wabbajack.Lib;
using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.ModListRegistry;
namespace Wabbajack.View_Models
{
public enum DownloadStatus
{
NotDownloaded,
Downloading,
Downloaded
}
public class ModListMetadataVM : ViewModel
{
public ModlistMetadata Metadata { get; }
private ModeSelectionVM _parent;
public ModListMetadataVM(ModeSelectionVM parent, ModlistMetadata metadata)
{
_parent = parent;
Metadata = metadata;
Click = ReactiveCommand.Create(() => this.DoClick());
}
private void DoClick()
{
switch (Status)
{
case DownloadStatus.NotDownloaded:
Download();
break;
case DownloadStatus.Downloading:
break;
case DownloadStatus.Downloaded:
Install();
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private void Install()
{
_parent.OpenInstaller(Location);
}
private void Download()
{
IsDownloading = true;
var queue = new WorkQueue(1);
var sub = queue.Status.Select(i => i.ProgressPercent).ToProperty(this, x => x.DownloadProgress);
queue.QueueTask(() =>
{
var downloader = DownloadDispatcher.ResolveArchive(Metadata.Links.Download);
downloader.Download(new Archive{ Name = Metadata.Title, Size = Metadata.DownloadMetadata?.Size ?? 0}, Location);
Location.FileHashCached();
IsDownloading = false;
sub.Dispose();
});
}
private void UpdateDownloadStatuses()
{
this.RaisePropertyChanged("Status");
this.RaisePropertyChanged("DownloadButtonVisibility");
this.RaisePropertyChanged("DownloadProgressVisibility");
this.RaisePropertyChanged("InstallButtonVisibility");
}
public string Location => Path.Combine(Consts.ModListDownloadFolder, Metadata.Links.MachineURL + ExtensionManager.Extension);
private bool _isDownloading = false;
public bool IsDownloading
{
get => _isDownloading;
private set
{
RaiseAndSetIfChanged(ref _isDownloading, value);
UpdateDownloadStatuses();
}
}
private float _downloadProgress;
public float DownloadProgress
{
get => _downloadProgress;
private set
{
RaiseAndSetIfChanged(ref _downloadProgress, value);
}
}
public DownloadStatus Status
{
get
{
if (IsDownloading) return DownloadStatus.Downloading;
if (!File.Exists(Location)) return DownloadStatus.NotDownloaded;
return Metadata.NeedsDownload(Location) ? DownloadStatus.NotDownloaded : DownloadStatus.Downloaded;
}
}
public Visibility DownloadButtonVisibility => Status == DownloadStatus.NotDownloaded ? Visibility.Visible : Visibility.Collapsed;
public Visibility DownloadProgressVisibility => Status == DownloadStatus.Downloading ? Visibility.Visible : Visibility.Collapsed;
public Visibility InstallButtonVisibility => Status == DownloadStatus.Downloaded ? Visibility.Visible : Visibility.Collapsed;
public ICommand Click { get; }
}
}

View File

@ -8,15 +8,13 @@ using System.Windows.Input;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Lib; using Wabbajack.Lib;
using Wabbajack.Lib.ModListRegistry; using Wabbajack.Lib.ModListRegistry;
using Wabbajack.View_Models;
namespace Wabbajack namespace Wabbajack
{ {
public class ModeSelectionVM : ViewModel public class ModeSelectionVM : ViewModel
{ {
public ObservableCollection<ModlistMetadata> ModLists { get; } = new ObservableCollection<ModlistMetadata>(ModlistMetadata.LoadFromGithub()); public ObservableCollection<ModListMetadataVM> ModLists { get; }
[Reactive]
public ModlistMetadata SelectedModList { get; set; }
private MainWindowVM _mainVM; private MainWindowVM _mainVM;
public ICommand DownloadAndInstallCommand { get; } public ICommand DownloadAndInstallCommand { get; }
@ -26,6 +24,9 @@ namespace Wabbajack
public ModeSelectionVM(MainWindowVM mainVM) public ModeSelectionVM(MainWindowVM mainVM)
{ {
_mainVM = mainVM; _mainVM = mainVM;
ModLists = new ObservableCollection<ModListMetadataVM>(ModlistMetadata.LoadFromGithub().Select(m => new ModListMetadataVM(this, m)));
InstallCommand = ReactiveCommand.Create( InstallCommand = ReactiveCommand.Create(
execute: () => execute: () =>
{ {
@ -43,18 +44,9 @@ namespace Wabbajack
{ {
mainVM.ActivePane = mainVM.Compiler.Value; mainVM.ActivePane = mainVM.Compiler.Value;
}); });
DownloadAndInstallCommand = ReactiveCommand.Create(
canExecute: this.WhenAny(x => x.SelectedModList)
.Select(x => x != null)
.ObserveOnGuiThread(),
execute: () =>
{
OpenInstaller(Download());
});
} }
private void OpenInstaller(string path) internal void OpenInstaller(string path)
{ {
if (path == null) return; if (path == null) return;
var installer = _mainVM.Installer.Value; var installer = _mainVM.Installer.Value;
@ -62,23 +54,5 @@ namespace Wabbajack
_mainVM.ActivePane = installer; _mainVM.ActivePane = installer;
installer.ModListPath.TargetPath = path; installer.ModListPath.TargetPath = path;
} }
private string Download()
{
if (!Directory.Exists(Consts.ModListDownloadFolder))
Directory.CreateDirectory(Consts.ModListDownloadFolder);
string dest = Path.Combine(Consts.ModListDownloadFolder, SelectedModList.Links.MachineURL + ExtensionManager.Extension);
var window = new DownloadWindow(SelectedModList.Links.Download,
SelectedModList.Title,
SelectedModList.Links.DownloadMetadata?.Size ?? 0,
dest);
window.ShowDialog();
if (window.Result == DownloadWindow.WindowResult.Completed)
return dest;
return null;
}
} }
} }

View File

@ -4,7 +4,9 @@
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:local="clr-namespace:Wabbajack" xmlns:local="clr-namespace:Wabbajack"
xmlns:ms="clr-namespace:Wabbajack.View_Models"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
d:DataContext="{d:DesignInstance local:ModeSelectionVM}" d:DataContext="{d:DesignInstance local:ModeSelectionVM}"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
@ -15,7 +17,6 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="70" /> <RowDefinition Height="70" />
<RowDefinition Height="70" /> <RowDefinition Height="70" />
<RowDefinition Height="70" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image <Image
Name="Banner" Name="Banner"
@ -34,8 +35,7 @@
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
ItemsSource="{Binding ModLists}" ItemsSource="{Binding ModLists}"
ScrollViewer.CanContentScroll="False" ScrollViewer.CanContentScroll="False"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
SelectedItem="{Binding Path=SelectedModList, Mode=TwoWay}">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid Margin="10"> <Grid Margin="10">
@ -50,27 +50,27 @@
<RowDefinition Height="20" /> <RowDefinition Height="20" />
<RowDefinition Height="15" /> <RowDefinition Height="15" />
<RowDefinition Height="150" /> <RowDefinition Height="150" />
<RowDefinition Height="20" /> <RowDefinition Height="30" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image <Image
Grid.Row="0" Grid.Row="0"
Grid.RowSpan="4" Grid.RowSpan="4"
Grid.Column="0" Grid.Column="0"
Source="{Binding Links.ImageUri}" /> Source="{Binding Metadata.Links.ImageUri}" />
<TextBlock <TextBlock
Grid.Row="0" Grid.Row="0"
Grid.Column="2" Grid.Column="2"
FontSize="20" FontSize="20"
Text="{Binding Title}" /> Text="{Binding Metadata.Title}" />
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="2" Grid.Column="2"
Text="{Binding Author}" /> Text="{Binding Metadata.Author}" />
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="4" Grid.Column="4"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Text="{Binding GameName}" Text="{Binding Metadata.GameName}"
TextAlignment="Right" /> TextAlignment="Right" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@ -78,24 +78,43 @@
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Top" VerticalAlignment="Top"
Text="{Binding Description}" Text="{Binding Metadata.Description}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<Button Grid.Row="3" Grid.Column="2">More Info</Button> <Button Grid.Row="3" Grid.ColumnSpan="5" Content="Download" Visibility="{Binding DownloadButtonVisibility}" Command="{Binding Click}" ></Button>
<mah:MetroProgressBar
Grid.Row="3"
Grid.ColumnSpan="5"
Background="{StaticResource WindowBackgroundBrush}"
BorderThickness="0"
Foreground="Transparent"
Maximum="1"
Value="{Binding DownloadProgress, Mode=OneWay}"
Visibility="{Binding DownloadProgressVisibility}" />
<mah:MetroProgressBar
Grid.Row="3"
Grid.ColumnSpan="5"
Background="Transparent"
BorderThickness="0"
Foreground="{StaticResource PrimaryVariantBrush}"
Maximum="1"
Opacity="{Binding DownloadProgress, Mode=OneWay}"
Value="{Binding DownloadProgress, Mode=OneWay}"
Visibility="{Binding DownloadProgressVisibility}" />
<Label Grid.Row="3"
Grid.ColumnSpan="5"
Content="Downloading..."
HorizontalContentAlignment="Center"
Visibility="{Binding DownloadProgressVisibility}" ></Label>
<Button Grid.Row="3" Grid.ColumnSpan ="5" Content="Install" Visibility="{Binding InstallButtonVisibility}" Command="{Binding Click}"></Button>
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>
<Button
Name="InstallModlist"
Grid.Row="2"
Grid.ColumnSpan="3"
Margin="2"
Command="{Binding DownloadAndInstallCommand}">
<TextBlock FontSize="40">Download and Install</TextBlock>
</Button>
<Button <Button
Name="InstallFromList" Name="InstallFromList"
Grid.Row="3" Grid.Row="2"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Margin="2" Margin="2"
Command="{Binding InstallCommand}"> Command="{Binding InstallCommand}">
@ -103,7 +122,7 @@
</Button> </Button>
<Button <Button
Name="CreateModlist" Name="CreateModlist"
Grid.Row="4" Grid.Row="3"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Margin="2" Margin="2"
Command="{Binding CompileCommand}"> Command="{Binding CompileCommand}">

View File

@ -169,6 +169,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="Converters\EqualsToBoolConverter.cs" /> <Compile Include="Converters\EqualsToBoolConverter.cs" />
<Compile Include="View Models\ModListMetadataVM.cs" />
<Compile Include="Views\LinksView.xaml.cs"> <Compile Include="Views\LinksView.xaml.cs">
<DependentUpon>LinksView.xaml</DependentUpon> <DependentUpon>LinksView.xaml</DependentUpon>
</Compile> </Compile>