wabbajack/Wabbajack.App.Wpf/View Models/Gallery/ModListMetadataVM.cs

238 lines
8.1 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using DynamicData;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.DTOs;
using Wabbajack.DTOs.ServerResponses;
using Wabbajack;
using Wabbajack.Extensions;
using Wabbajack.Messages;
using Wabbajack.Models;
using Wabbajack.Networking.WabbajackClientApi;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
using Wabbajack.RateLimiter;
using Wabbajack.Services.OSIntegrated.Services;
namespace Wabbajack
{
public struct ModListTag
{
public ModListTag(string name)
{
Name = name;
}
public string Name { get; }
}
public class ModListMetadataVM : ViewModel
{
public ModlistMetadata Metadata { get; }
private ModListGalleryVM _parent;
public ICommand OpenWebsiteCommand { get; }
public ICommand ExecuteCommand { get; }
public ICommand ModListContentsCommend { get; }
private readonly ObservableAsPropertyHelper<bool> _Exists;
public bool Exists => _Exists.Value;
public AbsolutePath Location { get; }
public LoadingLock LoadingImageLock { get; } = new();
[Reactive]
public List<ModListTag> ModListTagList { get; private set; }
[Reactive]
public Percent ProgressPercent { get; private set; }
[Reactive]
public bool IsBroken { get; private set; }
[Reactive]
public ModListStatus Status { get; set; }
[Reactive]
public bool IsDownloading { get; private set; }
[Reactive]
public string DownloadSizeText { get; private set; }
[Reactive]
public string InstallSizeText { get; private set; }
2022-11-05 19:25:31 +00:00
[Reactive]
public string TotalSizeRequirementText { get; private set; }
[Reactive]
public string VersionText { get; private set; }
Wabbajack 3.3.0.0 Update (#2416) * added more visible error messages to avoid user confusion added hard drive free space detection, added red error message text, removed overwrite checkbox, added wiki button link extended the error text for starting wabbajack in protected location removed debug code shortened error message to fit in text box * restored warning removed in error, updated changelog, removed debug includes * Update InstallerVM.cs * Update InstallerVM.cs * Update MainWindowViewModel.cs * added json optional flag to only show version number over modlist image in installer view, if the modlist image already contains the title removed debug code change to pascal case and match existing code style update changelog * Fix manual downloads sometimes launching in browser * Fix manual downloads from secure servers * Remove duplicate user agent code * Create configuration project and performance settings * Bind new performance settings to UI * Use performance settings to limit maximum memory per download * Remove unused settings and related classes * Updated CHANGELOG.md * update CHANGELOG.md * moved the existing files popup to an error message , heralding the return of the overwrite install checkbox * added newline * reverted erroneous edit * gogID for fallout4 added * update CHANGELOG.md * Fix deadlock when loading new settings * change folder/directory check logic * update CHANGELOG.md * revert unnecessary change * update CHANGELOG.md * Bump Wabbajack to .NET 7 * Bump ReactiveUI packages & deps * Update GameFinder to 4.0.0 * Update CHANGELOG.md * Update CHANGELOG.md --------- Co-authored-by: JanuarySnow <bobfordiscord12@gmail.com> Co-authored-by: JanuarySnow <85711747+JanuarySnow@users.noreply.github.com> Co-authored-by: UrbanCMC <UrbanCMC@web.de> Co-authored-by: trawzified <55751269+tr4wzified@users.noreply.github.com>
2023-10-12 18:33:06 +00:00
[Reactive]
public bool ImageContainsTitle { get; private set; }
[Reactive]
public bool DisplayVersionOnlyInInstallerView { get; private set; }
[Reactive]
public IErrorResponse Error { get; private set; }
private readonly ObservableAsPropertyHelper<BitmapImage> _Image;
public BitmapImage Image => _Image.Value;
private readonly ObservableAsPropertyHelper<bool> _LoadingImage;
public bool LoadingImage => _LoadingImage.Value;
private Subject<bool> IsLoadingIdle;
private readonly ILogger _logger;
private readonly ModListDownloadMaintainer _maintainer;
private readonly Client _wjClient;
private readonly CancellationToken _cancellationToken;
public ModListMetadataVM(ILogger logger, ModListGalleryVM parent, ModlistMetadata metadata,
ModListDownloadMaintainer maintainer, Client wjClient, CancellationToken cancellationToken)
{
_logger = logger;
_parent = parent;
_maintainer = maintainer;
Metadata = metadata;
_wjClient = wjClient;
_cancellationToken = cancellationToken;
2022-03-30 03:39:48 +00:00
Location = LauncherUpdater.CommonFolder.Value.Combine("downloaded_mod_lists", Metadata.NamespacedName).WithExtension(Ext.Wabbajack);
ModListTagList = new List<ModListTag>();
UpdateStatus().FireAndForget();
Metadata.Tags.ForEach(tag =>
{
ModListTagList.Add(new ModListTag(tag));
});
ModListTagList.Add(new ModListTag(metadata.Game.MetaData().HumanFriendlyGameName));
DownloadSizeText = "Download size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfArchives);
InstallSizeText = "Installation size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfInstalledFiles);
2022-11-05 19:25:31 +00:00
TotalSizeRequirementText = "Total size requirement: " + UIUtils.FormatBytes(
Metadata.DownloadMetadata.SizeOfArchives + Metadata.DownloadMetadata.SizeOfInstalledFiles
);
VersionText = "Modlist version : " + Metadata.Version;
Wabbajack 3.3.0.0 Update (#2416) * added more visible error messages to avoid user confusion added hard drive free space detection, added red error message text, removed overwrite checkbox, added wiki button link extended the error text for starting wabbajack in protected location removed debug code shortened error message to fit in text box * restored warning removed in error, updated changelog, removed debug includes * Update InstallerVM.cs * Update InstallerVM.cs * Update MainWindowViewModel.cs * added json optional flag to only show version number over modlist image in installer view, if the modlist image already contains the title removed debug code change to pascal case and match existing code style update changelog * Fix manual downloads sometimes launching in browser * Fix manual downloads from secure servers * Remove duplicate user agent code * Create configuration project and performance settings * Bind new performance settings to UI * Use performance settings to limit maximum memory per download * Remove unused settings and related classes * Updated CHANGELOG.md * update CHANGELOG.md * moved the existing files popup to an error message , heralding the return of the overwrite install checkbox * added newline * reverted erroneous edit * gogID for fallout4 added * update CHANGELOG.md * Fix deadlock when loading new settings * change folder/directory check logic * update CHANGELOG.md * revert unnecessary change * update CHANGELOG.md * Bump Wabbajack to .NET 7 * Bump ReactiveUI packages & deps * Update GameFinder to 4.0.0 * Update CHANGELOG.md * Update CHANGELOG.md --------- Co-authored-by: JanuarySnow <bobfordiscord12@gmail.com> Co-authored-by: JanuarySnow <85711747+JanuarySnow@users.noreply.github.com> Co-authored-by: UrbanCMC <UrbanCMC@web.de> Co-authored-by: trawzified <55751269+tr4wzified@users.noreply.github.com>
2023-10-12 18:33:06 +00:00
ImageContainsTitle = Metadata.ImageContainsTitle;
DisplayVersionOnlyInInstallerView = Metadata.DisplayVersionOnlyInInstallerView;
IsBroken = metadata.ValidationSummary.HasFailures || metadata.ForceDown;
// https://www.wabbajack.org/modlist/wj-featured/aldrnari
2023-01-16 11:06:48 +00:00
OpenWebsiteCommand = ReactiveCommand.Create(() => UIUtils.OpenWebsite(new Uri($"https://www.wabbajack.org/modlist/{Metadata.NamespacedName}")));
IsLoadingIdle = new Subject<bool>();
ModListContentsCommend = ReactiveCommand.Create(async () =>
{
UIUtils.OpenWebsite(new Uri($"https://www.wabbajack.org/search/{Metadata.NamespacedName}"));
}, IsLoadingIdle.StartWith(true));
ExecuteCommand = ReactiveCommand.CreateFromTask(async () =>
{
if (await _maintainer.HaveModList(Metadata))
{
LoadModlistForInstalling.Send(_maintainer.ModListPath(Metadata), Metadata);
NavigateToGlobal.Send(NavigateToGlobal.ScreenType.Installer);
}
else
{
await Download();
}
}, LoadingLock.WhenAnyValue(ll => ll.IsLoading)
.CombineLatest(this.WhenAnyValue(vm => vm.IsBroken))
.Select(v => !v.First && !v.Second));
_Exists = Observable.Interval(TimeSpan.FromSeconds(0.5))
.Unit()
.StartWith(Unit.Default)
.FlowSwitch(_parent.WhenAny(x => x.IsActive))
.SelectAsync(async _ =>
{
try
{
return !IsDownloading && await maintainer.HaveModList(metadata);
}
catch (Exception)
{
return true;
}
})
.ToGuiProperty(this, nameof(Exists));
var imageObs = Observable.Return(Metadata.Links.ImageUri)
.DownloadBitmapImage((ex) => _logger.LogError("Error downloading modlist image {Title}", Metadata.Title), LoadingImageLock);
_Image = imageObs
.ToGuiProperty(this, nameof(Image));
_LoadingImage = imageObs
.Select(x => false)
.StartWith(true)
.ToGuiProperty(this, nameof(LoadingImage));
}
private async Task Download()
{
2022-10-01 05:28:36 +00:00
try
{
Status = ModListStatus.Downloading;
2022-10-01 05:28:36 +00:00
using var ll = LoadingLock.WithLoading();
var (progress, task) = _maintainer.DownloadModlist(Metadata, _cancellationToken);
2022-10-01 05:28:36 +00:00
var dispose = progress
.BindToStrict(this, vm => vm.ProgressPercent);
try
{
await _wjClient.SendMetric("downloading", Metadata.Title);
await task;
await UpdateStatus();
}
finally
{
dispose.Dispose();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "While downloading {Modlist}", Metadata.RepositoryName);
await UpdateStatus();
}
}
private async Task UpdateStatus()
{
if (await _maintainer.HaveModList(Metadata))
Status = ModListStatus.Downloaded;
else if (LoadingLock.IsLoading)
Status = ModListStatus.Downloading;
else
Status = ModListStatus.NotDownloaded;
}
public enum ModListStatus
{
NotDownloaded,
Downloading,
Downloaded
}
}
}