mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Several UI fixes
This commit is contained in:
parent
5d1bc5ff3b
commit
295b629169
@ -48,10 +48,12 @@ public class SettingsManager
|
||||
try
|
||||
{
|
||||
if (path.FileExists())
|
||||
{
|
||||
await using (var s = path.Open(FileMode.Open))
|
||||
{
|
||||
return (await JsonSerializer.DeserializeAsync<T>(s, _dtos.Options))!;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -20,6 +20,7 @@ using Wabbajack.App.Utilities;
|
||||
using Wabbajack.App.ViewModels.SubViewModels;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Downloaders.GameFile;
|
||||
using Wabbajack.Downloaders.Interfaces;
|
||||
using Wabbajack.DTOs;
|
||||
using Wabbajack.DTOs.DownloadStates;
|
||||
using Wabbajack.DTOs.JsonConverters;
|
||||
@ -64,7 +65,7 @@ public class StandardInstallationViewModel : ViewModelBase
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
_updateTimer = new Timer(UpdateStatus, null, TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(250));
|
||||
_updateTimer = new Timer(UpdateStatus, null, TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(100));
|
||||
_updateTimer.DisposeWith(disposables);
|
||||
|
||||
_slideTimer = new Timer(_ =>
|
||||
@ -108,7 +109,7 @@ public class StandardInstallationViewModel : ViewModelBase
|
||||
[Reactive] public Percent StepProgress { get; set; } = Percent.Zero;
|
||||
|
||||
// Not Reactive, so we don't end up spamming the UI threads with events
|
||||
public StatusUpdate _latestStatus { get; set; } = new("", Percent.Zero, Percent.Zero);
|
||||
public StatusUpdate _latestStatus = new("", Percent.Zero, Percent.Zero);
|
||||
|
||||
public void Receive(StartInstallation msg)
|
||||
{
|
||||
@ -117,11 +118,12 @@ public class StandardInstallationViewModel : ViewModelBase
|
||||
|
||||
private void UpdateStatus(object? state)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() => {
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
StepsProgress = _latestStatus.StepsProgress;
|
||||
StepProgress = _latestStatus.StepProgress;
|
||||
StatusText = _latestStatus.StatusText;
|
||||
});
|
||||
}, DispatcherPriority.Render);
|
||||
}
|
||||
|
||||
private void NextSlide(int direction)
|
||||
|
@ -27,11 +27,13 @@ public class InstallConfigurationViewModel : ViewModelBase, IActivatableViewMode
|
||||
{
|
||||
private readonly DTOSerializer _dtos;
|
||||
private readonly InstallationStateManager _stateManager;
|
||||
private readonly SettingsManager _settingsManager;
|
||||
|
||||
|
||||
public InstallConfigurationViewModel(DTOSerializer dtos, InstallationStateManager stateManager)
|
||||
public InstallConfigurationViewModel(DTOSerializer dtos, InstallationStateManager stateManager, SettingsManager settingsManager)
|
||||
{
|
||||
_stateManager = stateManager;
|
||||
_settingsManager = settingsManager;
|
||||
|
||||
_dtos = dtos;
|
||||
Activator = new ViewModelActivator();
|
||||
@ -76,9 +78,20 @@ public class InstallConfigurationViewModel : ViewModelBase, IActivatableViewMode
|
||||
settings.Select(s => s!.Downloads)
|
||||
.BindTo(this, vm => vm.Download)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
|
||||
LoadSettings().FireAndForget();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private async Task LoadSettings()
|
||||
{
|
||||
var path = await _settingsManager.Load<AbsolutePath>("last-install-path");
|
||||
if (path != default && path.FileExists())
|
||||
ModListPath = path;
|
||||
}
|
||||
|
||||
[Reactive] public AbsolutePath ModListPath { get; set; }
|
||||
|
||||
[Reactive] public AbsolutePath Install { get; set; }
|
||||
@ -107,13 +120,15 @@ public class InstallConfigurationViewModel : ViewModelBase, IActivatableViewMode
|
||||
if (metadataPath.FileExists())
|
||||
metadata = _dtos.Deserialize<ModlistMetadata>(await metadataPath.ReadAllTextAsync());
|
||||
|
||||
_stateManager.SetLastState(new InstallationConfigurationSetting
|
||||
await _stateManager.SetLastState(new InstallationConfigurationSetting
|
||||
{
|
||||
ModList = ModListPath,
|
||||
Downloads = Download,
|
||||
Install = Install,
|
||||
Metadata = metadata
|
||||
}).FireAndForget();
|
||||
});
|
||||
|
||||
await _settingsManager.Save("last-install-path", ModListPath);
|
||||
|
||||
MessageBus.Current.SendMessage(new NavigateTo(typeof(StandardInstallationViewModel)));
|
||||
MessageBus.Current.SendMessage(new StartInstallation(ModListPath, Install, Download, metadata));
|
||||
|
@ -59,8 +59,8 @@ public class MainWindowViewModel : ReactiveValidationObject, IActivatableViewMod
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
BackButton = ReactiveCommand.Create(() => { Receive(new NavigateBack()); },
|
||||
this.ObservableForProperty(vm => vm.BreadCrumbs)
|
||||
.Select(bc => bc.Value.Count() > 1))
|
||||
this.WhenAnyValue(vm => vm.BreadCrumbs)
|
||||
.Select(bc => bc.Count() > 1))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
SettingsButton = ReactiveCommand.Create(() => { Receive(new NavigateTo(typeof(SettingsViewModel))); })
|
||||
|
@ -321,6 +321,6 @@ public class FileExtractor
|
||||
await using var stream = await factory.GetStream();
|
||||
await abs.WriteAllAsync(stream, token);
|
||||
return 0;
|
||||
}, token);
|
||||
}, token, progressFunction: updateProgress);
|
||||
}
|
||||
}
|
@ -87,7 +87,7 @@ public abstract class AInstaller<T>
|
||||
|
||||
public ModList ModList => _configuration.ModList;
|
||||
|
||||
public async Task NextStep(string statusText, long maxStepProgress)
|
||||
public void NextStep(string statusText, long maxStepProgress)
|
||||
{
|
||||
_updateStopWatch.Restart();
|
||||
MaxStepProgress = maxStepProgress;
|
||||
@ -109,11 +109,20 @@ public abstract class AInstaller<T>
|
||||
|
||||
public abstract Task<bool> Begin(CancellationToken token);
|
||||
|
||||
public async Task ExtractModlist(CancellationToken token)
|
||||
protected async Task ExtractModlist(CancellationToken token)
|
||||
{
|
||||
await NextStep("Extracting Modlist", 100);
|
||||
ExtractedModlistFolder = _manager.CreateFolder();
|
||||
await _extractor.ExtractAll(_configuration.ModlistArchive, ExtractedModlistFolder, token, updateProgress: p => UpdateProgress((long)(p.Value * 100)));
|
||||
await using var stream = _configuration.ModlistArchive.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
using var archive = new ZipArchive(stream, ZipArchiveMode.Read);
|
||||
NextStep("Extracting Modlist", archive.Entries.Count);
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
var path = entry.FullName.ToRelativePath().RelativeTo(ExtractedModlistFolder);
|
||||
path.Parent.CreateDirectory();
|
||||
await using var of = path.Open(FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
await entry.Open().CopyToAsync(of, token);
|
||||
UpdateProgress(1);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<byte[]> LoadBytesFromPath(RelativePath path)
|
||||
@ -157,7 +166,7 @@ public abstract class AInstaller<T>
|
||||
/// </summary>
|
||||
protected async Task PrimeVFS()
|
||||
{
|
||||
await NextStep("Priming VFS", 0);
|
||||
NextStep("Priming VFS", 0);
|
||||
_vfs.AddKnown(_configuration.ModList.Directives.OfType<FromArchive>().Select(d => d.ArchiveHashPath),
|
||||
HashedArchives);
|
||||
await _vfs.BackfillMissing();
|
||||
@ -165,7 +174,7 @@ public abstract class AInstaller<T>
|
||||
|
||||
public async Task BuildFolderStructure()
|
||||
{
|
||||
await NextStep("Building Folder Structure", 0);
|
||||
NextStep("Building Folder Structure", 0);
|
||||
_logger.LogInformation("Building Folder Structure");
|
||||
ModList.Directives
|
||||
.Where(d => d.To.Depth > 1)
|
||||
@ -176,7 +185,7 @@ public abstract class AInstaller<T>
|
||||
|
||||
public async Task InstallArchives(CancellationToken token)
|
||||
{
|
||||
await NextStep("Installing files", ModList.Directives.Sum(d => d.Size));
|
||||
NextStep("Installing files", ModList.Directives.Sum(d => d.Size));
|
||||
var grouped = ModList.Directives
|
||||
.OfType<FromArchive>()
|
||||
.Select(a => new {VF = _vfs.Index.FileForArchiveHashPath(a.ArchiveHashPath), Directive = a})
|
||||
@ -278,7 +287,7 @@ public abstract class AInstaller<T>
|
||||
}
|
||||
|
||||
_logger.LogInformation("Downloading {count} archives", missing.Count);
|
||||
await NextStep("Downloading files", missing.Count);
|
||||
NextStep("Downloading files", missing.Count);
|
||||
|
||||
await missing
|
||||
.OrderBy(a => a.Size)
|
||||
@ -339,7 +348,7 @@ public abstract class AInstaller<T>
|
||||
|
||||
public async Task HashArchives(CancellationToken token)
|
||||
{
|
||||
await NextStep("Hashing Archives", 0);
|
||||
NextStep("Hashing Archives", 0);
|
||||
_logger.LogInformation("Looking for files to hash");
|
||||
|
||||
var allFiles = _configuration.Downloads.EnumerateFiles()
|
||||
@ -390,7 +399,7 @@ public abstract class AInstaller<T>
|
||||
var savePath = (RelativePath) "saves";
|
||||
|
||||
var existingFiles = _configuration.Install.EnumerateFiles().ToList();
|
||||
await NextStep("Optimizing Modlist: Looking for files to delete", existingFiles.Count);
|
||||
NextStep("Optimizing Modlist: Looking for files to delete", existingFiles.Count);
|
||||
await existingFiles
|
||||
.PDoAll(async f =>
|
||||
{
|
||||
@ -409,7 +418,7 @@ public abstract class AInstaller<T>
|
||||
});
|
||||
|
||||
_logger.LogInformation("Cleaning empty folders");
|
||||
await NextStep("Optimizing Modlist: Cleaning empty folders", indexed.Keys.Count);
|
||||
NextStep("Optimizing Modlist: Cleaning empty folders", indexed.Keys.Count);
|
||||
var expectedFolders = (indexed.Keys
|
||||
.Select(f => f.RelativeTo(_configuration.Install))
|
||||
// We ignore the last part of the path, so we need a dummy file name
|
||||
@ -444,10 +453,9 @@ public abstract class AInstaller<T>
|
||||
|
||||
var existingfiles = _configuration.Install.EnumerateFiles().ToHashSet();
|
||||
|
||||
await NextStep("Optimizing Modlist: Removing redundant directives", indexed.Count);
|
||||
NextStep("Optimizing Modlist: Removing redundant directives", indexed.Count);
|
||||
await indexed.Values.PMapAll<Directive, Directive?>(async d =>
|
||||
{
|
||||
UpdateProgress(1);
|
||||
// Bit backwards, but we want to return null for
|
||||
// all files we *want* installed. We return the files
|
||||
// to remove from the install list.
|
||||
@ -458,12 +466,13 @@ public abstract class AInstaller<T>
|
||||
})
|
||||
.Do(d =>
|
||||
{
|
||||
UpdateProgress(1);
|
||||
if (d != null) indexed.Remove(d.To);
|
||||
});
|
||||
|
||||
_logger.LogInformation("Optimized {optimized} directives to {indexed} required", ModList.Directives.Length,
|
||||
indexed.Count);
|
||||
await NextStep("Finalizing modlist optimization", 0);
|
||||
NextStep("Finalizing modlist optimization", 0);
|
||||
var requiredArchives = indexed.Values.OfType<FromArchive>()
|
||||
.GroupBy(d => d.ArchiveHashPath.Hash)
|
||||
.Select(d => d.Key)
|
||||
|
@ -38,14 +38,14 @@ public class StandardInstaller : AInstaller<StandardInstaller>
|
||||
base(logger, config, gameLocator, extractor, jsonSerializer, vfs, fileHashCache, downloadDispatcher,
|
||||
parallelOptions, wjClient)
|
||||
{
|
||||
MaxSteps = 13;
|
||||
MaxSteps = 14;
|
||||
}
|
||||
|
||||
public override async Task<bool> Begin(CancellationToken token)
|
||||
{
|
||||
if (token.IsCancellationRequested) return false;
|
||||
await _wjClient.SendMetric(MetricNames.BeginInstall, ModList.Name);
|
||||
await NextStep("Configuring Installer", 0);
|
||||
NextStep("Configuring Installer", 0);
|
||||
_logger.LogInformation("Configuring Processor");
|
||||
|
||||
if (_configuration.GameFolder == default)
|
||||
@ -106,7 +106,7 @@ public class StandardInstaller : AInstaller<StandardInstaller>
|
||||
|
||||
await PrimeVFS();
|
||||
|
||||
BuildFolderStructure();
|
||||
await BuildFolderStructure();
|
||||
|
||||
await InstallArchives(token);
|
||||
|
||||
@ -129,7 +129,7 @@ public class StandardInstaller : AInstaller<StandardInstaller>
|
||||
await ExtractedModlistFolder!.DisposeAsync();
|
||||
await _wjClient.SendMetric(MetricNames.FinishInstall, ModList.Name);
|
||||
|
||||
await NextStep("Finished", 1);
|
||||
NextStep("Finished", 1);
|
||||
_logger.LogInformation("Finished Installation");
|
||||
return true;
|
||||
}
|
||||
@ -259,7 +259,7 @@ public class StandardInstaller : AInstaller<StandardInstaller>
|
||||
private async Task InstallIncludedFiles(CancellationToken token)
|
||||
{
|
||||
_logger.LogInformation("Writing inline files");
|
||||
await NextStep("Installing Included Files", ModList.Directives.OfType<InlineFile>().Count());
|
||||
NextStep("Installing Included Files", ModList.Directives.OfType<InlineFile>().Count());
|
||||
await ModList.Directives
|
||||
.OfType<InlineFile>()
|
||||
.PDoAll(async directive =>
|
||||
|
@ -30,7 +30,7 @@ public readonly struct Percent : IComparable, IEquatable<Percent>
|
||||
|
||||
public static bool InRange(double d)
|
||||
{
|
||||
return d >= 0 || d <= 1;
|
||||
return d is >= 0 or <= 1;
|
||||
}
|
||||
|
||||
public static Percent operator +(Percent c1, Percent c2)
|
||||
|
@ -172,7 +172,7 @@ public class Context
|
||||
_knownArchives.TryAdd(key, value);
|
||||
}
|
||||
|
||||
public async Task BackfillMissing()
|
||||
public async ValueTask BackfillMissing()
|
||||
{
|
||||
var newFiles = _knownArchives.ToDictionary(kv => kv.Key,
|
||||
kv => new VirtualFile
|
||||
|
Loading…
Reference in New Issue
Block a user