2020-01-18 19:50:40 +00:00
|
|
|
|
using System;
|
2019-11-29 05:52:33 +00:00
|
|
|
|
using System.Collections.Generic;
|
2019-11-30 09:08:04 +00:00
|
|
|
|
using System.Diagnostics;
|
2019-11-29 05:52:33 +00:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net;
|
2019-11-30 09:08:04 +00:00
|
|
|
|
using System.Reactive;
|
2019-11-29 05:52:33 +00:00
|
|
|
|
using System.Reactive.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows;
|
|
|
|
|
using System.Windows.Input;
|
2020-01-14 04:29:23 +00:00
|
|
|
|
using System.Windows.Media.Imaging;
|
2019-11-29 05:52:33 +00:00
|
|
|
|
using Alphaleonis.Win32.Filesystem;
|
|
|
|
|
using ReactiveUI;
|
2019-11-30 09:08:04 +00:00
|
|
|
|
using ReactiveUI.Fody.Helpers;
|
2019-11-29 05:52:33 +00:00
|
|
|
|
using Wabbajack.Common;
|
|
|
|
|
using Wabbajack.Lib;
|
|
|
|
|
using Wabbajack.Lib.Downloaders;
|
|
|
|
|
using Wabbajack.Lib.ModListRegistry;
|
|
|
|
|
|
2019-11-30 09:08:04 +00:00
|
|
|
|
namespace Wabbajack
|
2019-11-29 05:52:33 +00:00
|
|
|
|
{
|
2020-05-09 04:19:40 +00:00
|
|
|
|
|
|
|
|
|
public struct ModListTag
|
|
|
|
|
{
|
|
|
|
|
public ModListTag(string name)
|
|
|
|
|
{
|
|
|
|
|
Name = name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Name { get; }
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 05:52:33 +00:00
|
|
|
|
public class ModListMetadataVM : ViewModel
|
|
|
|
|
{
|
2019-11-30 09:08:04 +00:00
|
|
|
|
public ModlistMetadata Metadata { get; }
|
|
|
|
|
private ModListGalleryVM _parent;
|
2019-11-29 05:52:33 +00:00
|
|
|
|
|
2019-11-30 09:08:04 +00:00
|
|
|
|
public ICommand OpenWebsiteCommand { get; }
|
|
|
|
|
public ICommand ExecuteCommand { get; }
|
2019-11-29 05:52:33 +00:00
|
|
|
|
|
2019-11-30 09:08:04 +00:00
|
|
|
|
private readonly ObservableAsPropertyHelper<bool> _Exists;
|
|
|
|
|
public bool Exists => _Exists.Value;
|
2019-11-29 05:52:33 +00:00
|
|
|
|
|
2020-03-28 20:04:22 +00:00
|
|
|
|
public AbsolutePath Location { get; }
|
2019-11-29 05:52:33 +00:00
|
|
|
|
|
2020-05-09 04:19:40 +00:00
|
|
|
|
[Reactive]
|
|
|
|
|
public List<ModListTag> ModListTagList { get; private set; }
|
|
|
|
|
|
2019-11-30 09:08:04 +00:00
|
|
|
|
[Reactive]
|
2020-02-08 04:35:08 +00:00
|
|
|
|
public Percent ProgressPercent { get; private set; }
|
2019-11-30 09:08:04 +00:00
|
|
|
|
|
2019-12-17 04:06:30 +00:00
|
|
|
|
[Reactive]
|
|
|
|
|
public bool IsBroken { get; private set; }
|
2020-07-04 13:46:47 +00:00
|
|
|
|
|
|
|
|
|
[Reactive]
|
|
|
|
|
public bool IsDownloading { get; private set; }
|
2019-12-17 04:06:30 +00:00
|
|
|
|
|
2020-05-08 03:46:52 +00:00
|
|
|
|
[Reactive]
|
|
|
|
|
public string DownloadSizeText { get; private set; }
|
|
|
|
|
|
|
|
|
|
[Reactive]
|
|
|
|
|
public string InstallSizeText { get; private set; }
|
|
|
|
|
|
2020-01-14 04:57:12 +00:00
|
|
|
|
[Reactive]
|
|
|
|
|
public IErrorResponse Error { get; private set; }
|
|
|
|
|
|
2020-01-14 04:29:23 +00:00
|
|
|
|
private readonly ObservableAsPropertyHelper<BitmapImage> _Image;
|
|
|
|
|
public BitmapImage Image => _Image.Value;
|
|
|
|
|
|
2020-01-17 05:18:35 +00:00
|
|
|
|
private readonly ObservableAsPropertyHelper<bool> _LoadingImage;
|
|
|
|
|
public bool LoadingImage => _LoadingImage.Value;
|
|
|
|
|
|
2019-11-30 09:08:04 +00:00
|
|
|
|
public ModListMetadataVM(ModListGalleryVM parent, ModlistMetadata metadata)
|
2020-05-08 03:46:52 +00:00
|
|
|
|
{
|
2019-11-29 05:52:33 +00:00
|
|
|
|
_parent = parent;
|
|
|
|
|
Metadata = metadata;
|
2020-03-28 20:42:45 +00:00
|
|
|
|
Location = Consts.ModListDownloadFolder.Combine(Metadata.Links.MachineURL + (string)Consts.ModListExtension);
|
2020-05-09 04:19:40 +00:00
|
|
|
|
ModListTagList = new List<ModListTag>();
|
|
|
|
|
Metadata.tags.ForEach(tag =>
|
|
|
|
|
{
|
|
|
|
|
ModListTagList.Add(new ModListTag(tag));
|
|
|
|
|
});
|
2020-05-08 03:46:52 +00:00
|
|
|
|
DownloadSizeText = "Download size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfArchives);
|
|
|
|
|
InstallSizeText = "Installation size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfInstalledFiles);
|
2019-12-17 04:06:30 +00:00
|
|
|
|
IsBroken = metadata.ValidationSummary.HasFailures;
|
2020-06-13 19:13:21 +00:00
|
|
|
|
OpenWebsiteCommand = ReactiveCommand.Create(() => Utils.OpenWebsite(new Uri($"https://www.wabbajack.org/modlists/gallery/{Metadata.Links.MachineURL}")));
|
2019-12-20 05:09:53 +00:00
|
|
|
|
ExecuteCommand = ReactiveCommand.CreateFromObservable<Unit, Unit>(
|
2019-12-17 04:06:30 +00:00
|
|
|
|
canExecute: this.WhenAny(x => x.IsBroken).Select(x => !x),
|
|
|
|
|
execute: (unit) =>
|
2019-11-30 09:08:04 +00:00
|
|
|
|
Observable.Return(unit)
|
|
|
|
|
.WithLatestFrom(
|
|
|
|
|
this.WhenAny(x => x.Exists),
|
|
|
|
|
(_, e) => e)
|
|
|
|
|
// Do any download work on background thread
|
|
|
|
|
.ObserveOn(RxApp.TaskpoolScheduler)
|
|
|
|
|
.SelectTask(async (exists) =>
|
|
|
|
|
{
|
|
|
|
|
if (!exists)
|
|
|
|
|
{
|
2020-01-14 04:57:12 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2020-01-18 20:52:37 +00:00
|
|
|
|
var success = await Download();
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
Error = ErrorResponse.Fail("Download was marked unsuccessful");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-01-14 04:57:12 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Error = ErrorResponse.Fail(ex);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-11-30 09:08:04 +00:00
|
|
|
|
// Return an updated check on exists
|
2020-03-28 20:04:22 +00:00
|
|
|
|
return Location.Exists;
|
2019-11-30 09:08:04 +00:00
|
|
|
|
}
|
|
|
|
|
return exists;
|
|
|
|
|
})
|
2019-12-20 05:09:53 +00:00
|
|
|
|
.Where(exists => exists)
|
2019-11-30 09:08:04 +00:00
|
|
|
|
// Do any install page swap over on GUI thread
|
|
|
|
|
.ObserveOnGuiThread()
|
2019-12-20 05:09:53 +00:00
|
|
|
|
.Select(_ =>
|
2019-11-30 09:08:04 +00:00
|
|
|
|
{
|
2020-03-28 20:04:22 +00:00
|
|
|
|
_parent.MWVM.OpenInstaller(Location);
|
2019-12-20 05:09:53 +00:00
|
|
|
|
|
|
|
|
|
// Wait for modlist member to be filled, then open its readme
|
|
|
|
|
return _parent.MWVM.Installer.Value.WhenAny(x => x.ModList)
|
|
|
|
|
.NotNull()
|
|
|
|
|
.Take(1)
|
|
|
|
|
.Do(modList =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-04-15 17:40:41 +00:00
|
|
|
|
modList.OpenReadme();
|
2019-12-20 05:09:53 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Utils.Error(ex);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.Switch()
|
|
|
|
|
.Unit());
|
2019-11-30 09:08:04 +00:00
|
|
|
|
|
|
|
|
|
_Exists = Observable.Interval(TimeSpan.FromSeconds(0.5))
|
|
|
|
|
.Unit()
|
|
|
|
|
.StartWith(Unit.Default)
|
2020-01-14 05:17:54 +00:00
|
|
|
|
.FlowSwitch(_parent.WhenAny(x => x.IsActive))
|
2020-05-25 17:34:25 +00:00
|
|
|
|
.SelectAsync(async _ =>
|
2019-12-20 04:07:53 +00:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-07-04 13:46:47 +00:00
|
|
|
|
return !IsDownloading && !(await metadata.NeedsDownload(Location));
|
2019-12-20 04:07:53 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
})
|
2020-01-17 04:48:54 +00:00
|
|
|
|
.ToGuiProperty(this, nameof(Exists));
|
2020-01-14 04:29:23 +00:00
|
|
|
|
|
2020-01-17 05:18:35 +00:00
|
|
|
|
var imageObs = Observable.Return(Metadata.Links.ImageUri)
|
|
|
|
|
.DownloadBitmapImage((ex) => Utils.Log($"Error downloading modlist image {Metadata.Title}"));
|
|
|
|
|
|
|
|
|
|
_Image = imageObs
|
2020-01-17 04:48:54 +00:00
|
|
|
|
.ToGuiProperty(this, nameof(Image));
|
2020-01-17 05:18:35 +00:00
|
|
|
|
|
|
|
|
|
_LoadingImage = imageObs
|
|
|
|
|
.Select(x => false)
|
|
|
|
|
.StartWith(true)
|
|
|
|
|
.ToGuiProperty(this, nameof(LoadingImage));
|
2019-11-29 05:52:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-18 20:52:37 +00:00
|
|
|
|
private async Task<bool> Download()
|
2019-11-29 05:52:33 +00:00
|
|
|
|
{
|
2020-02-08 04:35:08 +00:00
|
|
|
|
ProgressPercent = Percent.Zero;
|
2020-01-18 19:50:40 +00:00
|
|
|
|
using (var queue = new WorkQueue(1))
|
|
|
|
|
using (queue.Status.Select(i => i.ProgressPercent)
|
2020-05-12 23:41:39 +00:00
|
|
|
|
.ObserveOnGuiThread()
|
2020-01-18 19:50:40 +00:00
|
|
|
|
.Subscribe(percent => ProgressPercent = percent))
|
2019-11-29 05:52:33 +00:00
|
|
|
|
{
|
2020-01-18 19:50:40 +00:00
|
|
|
|
var tcs = new TaskCompletionSource<bool>();
|
|
|
|
|
queue.QueueTask(async () =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-07-04 13:46:47 +00:00
|
|
|
|
IsDownloading = true;
|
2020-06-29 22:18:29 +00:00
|
|
|
|
Utils.Log($"Starting Download of {Metadata.Links.MachineURL}");
|
2020-01-18 19:50:40 +00:00
|
|
|
|
var downloader = DownloadDispatcher.ResolveArchive(Metadata.Links.Download);
|
2020-07-04 13:46:47 +00:00
|
|
|
|
var result = await downloader.Download(
|
|
|
|
|
new Archive(state: null!)
|
|
|
|
|
{
|
|
|
|
|
Name = Metadata.Title, Size = Metadata.DownloadMetadata?.Size ?? 0
|
|
|
|
|
}, Location);
|
2020-06-29 22:18:29 +00:00
|
|
|
|
Utils.Log($"Done downloading {Metadata.Links.MachineURL}");
|
|
|
|
|
|
2020-01-18 20:52:37 +00:00
|
|
|
|
// Want to rehash to current file, even if failed?
|
2020-05-25 17:34:25 +00:00
|
|
|
|
await Location.FileHashCachedAsync();
|
2020-06-29 22:18:29 +00:00
|
|
|
|
Utils.Log($"Done hashing {Metadata.Links.MachineURL}");
|
2020-01-18 20:52:37 +00:00
|
|
|
|
tcs.SetResult(result);
|
2020-01-18 19:50:40 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2020-07-04 13:46:47 +00:00
|
|
|
|
Utils.Error(ex, $"Error Downloading of {Metadata.Links.MachineURL}");
|
2020-01-18 19:50:40 +00:00
|
|
|
|
tcs.SetException(ex);
|
|
|
|
|
}
|
2020-07-04 13:46:47 +00:00
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
IsDownloading = false;
|
|
|
|
|
}
|
2020-01-18 19:50:40 +00:00
|
|
|
|
});
|
|
|
|
|
|
2020-01-19 18:38:55 +00:00
|
|
|
|
|
2020-06-14 13:13:29 +00:00
|
|
|
|
Task.Run(async () => await Metrics.Send(Metrics.Downloading, Metadata.Title))
|
2020-01-19 18:38:55 +00:00
|
|
|
|
.FireAndForget(ex => Utils.Error(ex, "Error sending download metric"));
|
2020-01-18 20:52:37 +00:00
|
|
|
|
|
|
|
|
|
return await tcs.Task;
|
2020-01-18 19:50:40 +00:00
|
|
|
|
}
|
2019-11-29 05:52:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|