mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Merge branch 'master' into morrowind-bsas
This commit is contained in:
commit
98b7ba4752
@ -12,7 +12,8 @@ namespace Wabbajack.CLI
|
|||||||
typeof(Validate),
|
typeof(Validate),
|
||||||
typeof(DownloadUrl),
|
typeof(DownloadUrl),
|
||||||
typeof(UpdateModlists),
|
typeof(UpdateModlists),
|
||||||
typeof(UpdateNexusCache)
|
typeof(UpdateNexusCache),
|
||||||
|
typeof(ChangeDownload)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ namespace Wabbajack.CLI
|
|||||||
(DownloadUrl opts) => opts.Execute(),
|
(DownloadUrl opts) => opts.Execute(),
|
||||||
(UpdateModlists opts) => opts.Execute(),
|
(UpdateModlists opts) => opts.Execute(),
|
||||||
(UpdateNexusCache opts) => opts.Execute(),
|
(UpdateNexusCache opts) => opts.Execute(),
|
||||||
|
(ChangeDownload opts) => opts.Execute(),
|
||||||
errs => 1);
|
errs => 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
359
Wabbajack.CLI/Verbs/ChangeDownload.cs
Normal file
359
Wabbajack.CLI/Verbs/ChangeDownload.cs
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Alphaleonis.Win32.Filesystem;
|
||||||
|
using CommandLine;
|
||||||
|
using Wabbajack.Common;
|
||||||
|
using Wabbajack.Lib;
|
||||||
|
using Directory = Alphaleonis.Win32.Filesystem.Directory;
|
||||||
|
using File = Alphaleonis.Win32.Filesystem.File;
|
||||||
|
using Path = Alphaleonis.Win32.Filesystem.Path;
|
||||||
|
|
||||||
|
namespace Wabbajack.CLI.Verbs
|
||||||
|
{
|
||||||
|
[Verb("change-download", HelpText = "Move or Copy all used Downloads from a Modlist to another directory")]
|
||||||
|
public class ChangeDownload : AVerb
|
||||||
|
{
|
||||||
|
[Option("input", Required = true, HelpText = "Input folder containing the downloads you want to move")]
|
||||||
|
public string Input { get; set; }
|
||||||
|
|
||||||
|
[Option("output", Required = true, HelpText = "Output folder the downloads should be transferred to")]
|
||||||
|
public string Output { get; set; }
|
||||||
|
|
||||||
|
[Option("modlist", Required = true, HelpText = "The Modlist, can either be a .wabbajack or a modlist.txt file")]
|
||||||
|
public string Modlist { get; set; }
|
||||||
|
|
||||||
|
[Option("mods", Required = false, HelpText = "Mods folder location if the provided modlist file is an MO2 modlist.txt")]
|
||||||
|
public string Mods { get; set; }
|
||||||
|
|
||||||
|
[Option("copy", Default = true, HelpText = "Whether to copy the files")]
|
||||||
|
public bool Copy { get; set; }
|
||||||
|
|
||||||
|
[Option("move", Default = false, HelpText = "Whether to move the files")]
|
||||||
|
public bool Move { get; set; }
|
||||||
|
|
||||||
|
[Option("overwrite", Default = false, HelpText = "Whether to overwrite the file if it already exists")]
|
||||||
|
public bool Overwrite { get; set; }
|
||||||
|
|
||||||
|
[Option("meta", Default = true, HelpText = "Whether to also transfer the meta file for the archive")]
|
||||||
|
public bool IncludeMeta { get; set; }
|
||||||
|
|
||||||
|
private static void Log(string msg)
|
||||||
|
{
|
||||||
|
Console.WriteLine(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct TransferFile
|
||||||
|
{
|
||||||
|
public readonly string Input;
|
||||||
|
public readonly string Output;
|
||||||
|
public readonly bool IsMeta;
|
||||||
|
|
||||||
|
public TransferFile(string input, string output, bool isMeta = false)
|
||||||
|
{
|
||||||
|
Input = input;
|
||||||
|
Output = output;
|
||||||
|
IsMeta = isMeta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<int> Run()
|
||||||
|
{
|
||||||
|
if (!File.Exists(Modlist))
|
||||||
|
{
|
||||||
|
Log($"The file {Modlist} does not exist!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(Input))
|
||||||
|
{
|
||||||
|
Log($"The input directory {Input} does not exist!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(Output))
|
||||||
|
{
|
||||||
|
Log($"The output directory {Output} does not exist, it will be created.");
|
||||||
|
Directory.CreateDirectory(Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Modlist.EndsWith(Consts.ModListExtension) && !Modlist.EndsWith("modlist.txt"))
|
||||||
|
{
|
||||||
|
Log($"The file {Modlist} is not a valid modlist file!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Copy && Move)
|
||||||
|
{
|
||||||
|
Log("You can't set both copy and move flags!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isModlist = Modlist.EndsWith(Consts.ModListExtension);
|
||||||
|
|
||||||
|
var list = new List<TransferFile>();
|
||||||
|
|
||||||
|
if (isModlist)
|
||||||
|
{
|
||||||
|
ModList modlist;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
modlist = AInstaller.LoadFromFile(Input);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log($"Error while loading the Modlist!\n{e}");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modlist == null)
|
||||||
|
{
|
||||||
|
Log("The Modlist could not be loaded!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log($"Modlist contains {modlist.Archives.Count} archives.");
|
||||||
|
|
||||||
|
modlist.Archives.Do(a =>
|
||||||
|
{
|
||||||
|
var inputPath = Path.Combine(Input, a.Name);
|
||||||
|
var outputPath = Path.Combine(Output, a.Name);
|
||||||
|
|
||||||
|
if (!File.Exists(inputPath))
|
||||||
|
{
|
||||||
|
Log($"File {inputPath} does not exist, skipping.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log($"Adding {inputPath} to the transfer list.");
|
||||||
|
list.Add(new TransferFile(inputPath, outputPath));
|
||||||
|
|
||||||
|
var metaInputPath = Path.Combine(inputPath, ".meta");
|
||||||
|
var metaOutputPath = Path.Combine(outputPath, ".meta");
|
||||||
|
|
||||||
|
if (File.Exists(metaInputPath))
|
||||||
|
{
|
||||||
|
Log($"Found meta file {metaInputPath}");
|
||||||
|
if (IncludeMeta)
|
||||||
|
{
|
||||||
|
Log($"Adding {metaInputPath} to the transfer list.");
|
||||||
|
list.Add(new TransferFile(metaInputPath, metaOutputPath));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log($"Meta file {metaInputPath} will be ignored.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log($"Found no meta file for {inputPath}");
|
||||||
|
if (IncludeMeta)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(a.Meta))
|
||||||
|
{
|
||||||
|
Log($"Meta for {a.Name} is empty, this should not be possible but whatever.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("Adding meta from archive info the transfer list");
|
||||||
|
list.Add(new TransferFile(a.Meta, metaOutputPath, true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log($"Meta will be ignored for {a.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(Mods))
|
||||||
|
{
|
||||||
|
Log($"Mods directory {Mods} does not exist!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log($"Reading modlist.txt from {Modlist}");
|
||||||
|
string[] modlist = File.ReadAllLines(Modlist);
|
||||||
|
|
||||||
|
if (modlist == null || modlist.Length == 0)
|
||||||
|
{
|
||||||
|
Log($"Provided modlist.txt file at {Modlist} is empty or could not be read!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mods = modlist.Where(s => s.StartsWith("+")).Select(s => s.Substring(1)).ToHashSet();
|
||||||
|
if (mods.Count == 0)
|
||||||
|
{
|
||||||
|
Log("Counted mods from modlist.txt are 0!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log($"Found {mods.Count} mods in modlist.txt");
|
||||||
|
|
||||||
|
var downloads = new HashSet<string>();
|
||||||
|
|
||||||
|
Directory.EnumerateDirectories(Mods, "*", SearchOption.TopDirectoryOnly)
|
||||||
|
.Where(d => mods.Contains(Path.GetRelativePath(Path.GetDirectoryName(d), d)))
|
||||||
|
.Do(d =>
|
||||||
|
{
|
||||||
|
var meta = Path.Combine(d, "meta.ini");
|
||||||
|
if (!File.Exists(meta))
|
||||||
|
{
|
||||||
|
Log($"Mod meta file {meta} does not exist, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] ini = File.ReadAllLines(meta);
|
||||||
|
if (ini == null || ini.Length == 0)
|
||||||
|
{
|
||||||
|
Log($"Mod meta file {meta} could not be read or is empty!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ini.Where(i => !string.IsNullOrWhiteSpace(i) && i.StartsWith("installationFile="))
|
||||||
|
.Select(i => i.Replace("installationFile=", ""))
|
||||||
|
.Do(i =>
|
||||||
|
{
|
||||||
|
Log($"Found installationFile {i}");
|
||||||
|
downloads.Add(i);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Log($"Found {downloads.Count} installationFiles from mod metas.");
|
||||||
|
|
||||||
|
Directory.EnumerateFiles(Input, "*", SearchOption.TopDirectoryOnly)
|
||||||
|
.Where(f => downloads.Contains(Path.GetFileNameWithoutExtension(f)))
|
||||||
|
.Do(f =>
|
||||||
|
{
|
||||||
|
Log($"Found archive {f}");
|
||||||
|
|
||||||
|
var outputPath = Path.Combine(Output, Path.GetFileName(f));
|
||||||
|
|
||||||
|
Log($"Adding {f} to the transfer list");
|
||||||
|
list.Add(new TransferFile(f, outputPath));
|
||||||
|
|
||||||
|
var metaInputPath = Path.Combine(f, ".meta");
|
||||||
|
if (File.Exists(metaInputPath))
|
||||||
|
{
|
||||||
|
Log($"Found meta file for {f} at {metaInputPath}");
|
||||||
|
if (IncludeMeta)
|
||||||
|
{
|
||||||
|
var metaOutputPath = Path.Combine(outputPath, ".meta");
|
||||||
|
Log($"Adding {metaInputPath} to the transfer list.");
|
||||||
|
list.Add(new TransferFile(metaInputPath, metaOutputPath));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log("Meta file will be ignored");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log($"Found no meta file for {f}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Log($"Transfer list contains {list.Count} items");
|
||||||
|
var success = 0;
|
||||||
|
var failed = 0;
|
||||||
|
var skipped = 0;
|
||||||
|
list.Do(f =>
|
||||||
|
{
|
||||||
|
if (File.Exists(f.Output))
|
||||||
|
{
|
||||||
|
if (Overwrite)
|
||||||
|
{
|
||||||
|
Log($"Output file {f.Output} already exists, it will be overwritten");
|
||||||
|
if (f.IsMeta || Move)
|
||||||
|
{
|
||||||
|
Log($"Deleting file at {f.Output}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(f.Output);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log($"Could not delete file {f.Output}!\n{e}");
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log($"Output file {f.Output} already exists, skipping");
|
||||||
|
skipped++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.IsMeta)
|
||||||
|
{
|
||||||
|
Log($"Writing meta data to {f.Output}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.WriteAllText(f.Output, f.Input, Encoding.UTF8);
|
||||||
|
success++;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log($"Error while writing meta data to {f.Output}!\n{e}");
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Copy)
|
||||||
|
{
|
||||||
|
Log($"Copying file {f.Input} to {f.Output}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Copy(f.Input, f.Output, Overwrite ? CopyOptions.None : CopyOptions.FailIfExists, CopyMoveProgressHandler, null);
|
||||||
|
success++;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log($"Error while copying file {f.Input} to {f.Output}!\n{e}");
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(Move)
|
||||||
|
{
|
||||||
|
Log($"Moving file {f.Input} to {f.Output}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Move(f.Input, f.Output, Overwrite ? MoveOptions.ReplaceExisting : MoveOptions.None, CopyMoveProgressHandler, null);
|
||||||
|
success++;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log($"Error while moving file {f.Input} to {f.Output}!\n{e}");
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Log($"Skipped transfers: {skipped}");
|
||||||
|
Log($"Failed transfers: {failed}");
|
||||||
|
Log($"Successful transfers: {success}");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CopyMoveProgressResult CopyMoveProgressHandler(long totalfilesize, long totalbytestransferred, long streamsize, long streambytestransferred, int streamnumber, CopyMoveProgressCallbackReason callbackreason, object userdata)
|
||||||
|
{
|
||||||
|
Console.Write($"\r{' ', 100}");
|
||||||
|
|
||||||
|
Console.Write(totalfilesize == totalbytestransferred
|
||||||
|
? "\rTransfer complete!\n"
|
||||||
|
: $"\rTotal Size: {totalfilesize}, Transferred: {totalbytestransferred}");
|
||||||
|
return CopyMoveProgressResult.Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@ namespace Wabbajack.Lib
|
|||||||
typeof(PropertyFile), typeof(SteamMeta), typeof(SteamWorkshopDownloader), typeof(SteamWorkshopDownloader.State),
|
typeof(PropertyFile), typeof(SteamMeta), typeof(SteamWorkshopDownloader), typeof(SteamWorkshopDownloader.State),
|
||||||
typeof(LoversLabDownloader.State), typeof(GameFileSourceDownloader.State), typeof(VectorPlexusDownloader.State),
|
typeof(LoversLabDownloader.State), typeof(GameFileSourceDownloader.State), typeof(VectorPlexusDownloader.State),
|
||||||
typeof(DeadlyStreamDownloader.State), typeof(AFKModsDownloader.State), typeof(TESAllianceDownloader.State),
|
typeof(DeadlyStreamDownloader.State), typeof(AFKModsDownloader.State), typeof(TESAllianceDownloader.State),
|
||||||
typeof(TES3ArchiveState), typeof(TES3FileState)
|
typeof(TES3ArchiveState), typeof(TES3FileState), typeof(BethesdaNetDownloader.State)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Config.VersionTolerance.Mode = VersionToleranceMode.Standard;
|
Config.VersionTolerance.Mode = VersionToleranceMode.Standard;
|
||||||
|
@ -131,7 +131,7 @@ namespace Wabbajack.Lib
|
|||||||
if (Directory.Exists(ModListOutputFolder))
|
if (Directory.Exists(ModListOutputFolder))
|
||||||
Utils.DeleteDirectory(ModListOutputFolder);
|
Utils.DeleteDirectory(ModListOutputFolder);
|
||||||
|
|
||||||
/*
|
|
||||||
if (cancel.IsCancellationRequested) return false;
|
if (cancel.IsCancellationRequested) return false;
|
||||||
UpdateTracker.NextStep("Inferring metas for game file downloads");
|
UpdateTracker.NextStep("Inferring metas for game file downloads");
|
||||||
await InferMetas();
|
await InferMetas();
|
||||||
@ -139,8 +139,8 @@ namespace Wabbajack.Lib
|
|||||||
if (cancel.IsCancellationRequested) return false;
|
if (cancel.IsCancellationRequested) return false;
|
||||||
UpdateTracker.NextStep("Reindexing downloads after meta inferring");
|
UpdateTracker.NextStep("Reindexing downloads after meta inferring");
|
||||||
await VFS.AddRoot(MO2DownloadsFolder);
|
await VFS.AddRoot(MO2DownloadsFolder);
|
||||||
await VFS.WriteToFile(_vfsCacheName);
|
await VFS.WriteToFile(VFSCacheName);
|
||||||
*/
|
|
||||||
|
|
||||||
if (cancel.IsCancellationRequested) return false;
|
if (cancel.IsCancellationRequested) return false;
|
||||||
UpdateTracker.NextStep("Pre-validating Archives");
|
UpdateTracker.NextStep("Pre-validating Archives");
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reactive;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
@ -9,8 +10,10 @@ using Wabbajack.Lib;
|
|||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
{
|
{
|
||||||
|
public enum SortBy { Name, Size }
|
||||||
|
|
||||||
public class ManifestVM : ViewModel
|
public class ManifestVM : ViewModel
|
||||||
{
|
{
|
||||||
public Manifest Manifest { get; set; }
|
public Manifest Manifest { get; set; }
|
||||||
|
|
||||||
public string Name => !string.IsNullOrWhiteSpace(Manifest.Name) ? Manifest.Name : "Wabbajack Modlist";
|
public string Name => !string.IsNullOrWhiteSpace(Manifest.Name) ? Manifest.Name : "Wabbajack Modlist";
|
||||||
@ -27,28 +30,73 @@ namespace Wabbajack
|
|||||||
private readonly ObservableAsPropertyHelper<IEnumerable<Archive>> _searchResults;
|
private readonly ObservableAsPropertyHelper<IEnumerable<Archive>> _searchResults;
|
||||||
public IEnumerable<Archive> SearchResults => _searchResults.Value;
|
public IEnumerable<Archive> SearchResults => _searchResults.Value;
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool SortAscending { get; set; } = true;
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public SortBy SortEnum { get; set; } = SortBy.Name;
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> SortByNameCommand;
|
||||||
|
public ReactiveCommand<Unit, Unit> SortBySizeCommand;
|
||||||
|
|
||||||
|
private IEnumerable<Archive> Order(IEnumerable<Archive> list)
|
||||||
|
{
|
||||||
|
if (SortAscending)
|
||||||
|
{
|
||||||
|
return SortEnum switch
|
||||||
|
{
|
||||||
|
SortBy.Name => list.OrderBy(x => x.Name),
|
||||||
|
SortBy.Size => list.OrderBy(x => x.Size),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return SortEnum switch
|
||||||
|
{
|
||||||
|
SortBy.Name => list.OrderByDescending(x => x.Name),
|
||||||
|
SortBy.Size => list.OrderByDescending(x => x.Size),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Swap(SortBy to)
|
||||||
|
{
|
||||||
|
if (SortEnum != to)
|
||||||
|
SortEnum = to;
|
||||||
|
else
|
||||||
|
SortAscending = !SortAscending;
|
||||||
|
}
|
||||||
|
|
||||||
public ManifestVM(Manifest manifest)
|
public ManifestVM(Manifest manifest)
|
||||||
{
|
{
|
||||||
Manifest = manifest;
|
Manifest = manifest;
|
||||||
|
|
||||||
|
SortByNameCommand = ReactiveCommand.Create(() => Swap(SortBy.Name));
|
||||||
|
|
||||||
|
SortBySizeCommand = ReactiveCommand.Create(() => Swap(SortBy.Size));
|
||||||
|
|
||||||
_searchResults =
|
_searchResults =
|
||||||
this.WhenAnyValue(x => x.SearchTerm)
|
this.WhenAnyValue(x => x.SearchTerm)
|
||||||
|
.CombineLatest(
|
||||||
|
this.WhenAnyValue(x => x.SortAscending),
|
||||||
|
this.WhenAnyValue(x => x.SortEnum),
|
||||||
|
(term, ascending, sort) => term)
|
||||||
.Throttle(TimeSpan.FromMilliseconds(800))
|
.Throttle(TimeSpan.FromMilliseconds(800))
|
||||||
.Select(term => term?.Trim())
|
.Select(term => term?.Trim())
|
||||||
.DistinctUntilChanged()
|
//.DistinctUntilChanged()
|
||||||
.Select(term =>
|
.Select(term =>
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(term))
|
if (string.IsNullOrWhiteSpace(term))
|
||||||
return Archives;
|
return Order(Archives);
|
||||||
|
|
||||||
return Archives.Where(x =>
|
return Order(Archives.Where(x =>
|
||||||
{
|
{
|
||||||
if (term.StartsWith("hash:"))
|
if (term.StartsWith("hash:"))
|
||||||
return x.Hash.StartsWith(term.Replace("hash:", ""));
|
return x.Hash.StartsWith(term.Replace("hash:", ""));
|
||||||
return x.Name.StartsWith(term);
|
return x.Name.StartsWith(term);
|
||||||
});
|
}));
|
||||||
})
|
})
|
||||||
.ToGuiProperty(this, nameof(SearchResults), Archives);
|
.ToGuiProperty(this, nameof(SearchResults), Order(Archives));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,16 @@
|
|||||||
<TextBlock Padding="6 0 0 0" FontSize="20" Text="Search:"/>
|
<TextBlock Padding="6 0 0 0" FontSize="20" Text="Search:"/>
|
||||||
<TextBox x:Name="SearchBar" BorderThickness="2" BorderBrush="{StaticResource SearchBarBrush}" FontSize="16" MaxLength="100"/>
|
<TextBox x:Name="SearchBar" BorderThickness="2" BorderBrush="{StaticResource SearchBarBrush}" FontSize="16" MaxLength="100"/>
|
||||||
|
|
||||||
|
<StackPanel Margin="6 6 0 0" Orientation="Horizontal">
|
||||||
|
<TextBlock Padding="0 1 0 0" FontSize="14">Order by: </TextBlock>
|
||||||
|
<Button x:Name="OrderByNameButton" Padding="4 0 4 0">
|
||||||
|
<TextBlock FontSize="14">Name</TextBlock>
|
||||||
|
</Button>
|
||||||
|
<Button x:Name="OrderBySizeButton">
|
||||||
|
<TextBlock FontSize="14">Size</TextBlock>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<ItemsControl Padding="0 3 0 6" x:Name="ModsList">
|
<ItemsControl Padding="0 3 0 6" x:Name="ModsList">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
|
@ -5,11 +5,8 @@ using System.Windows;
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Wabbajack.Common;
|
|
||||||
using Wabbajack.Lib;
|
using Wabbajack.Lib;
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
@ -44,6 +41,10 @@ namespace Wabbajack
|
|||||||
.DisposeWith(disposable);
|
.DisposeWith(disposable);
|
||||||
this.Bind(ViewModel, x => x.SearchTerm, x => x.SearchBar.Text)
|
this.Bind(ViewModel, x => x.SearchTerm, x => x.SearchBar.Text)
|
||||||
.DisposeWith(disposable);
|
.DisposeWith(disposable);
|
||||||
|
this.BindCommand(ViewModel, x => x.SortByNameCommand, x => x.OrderByNameButton)
|
||||||
|
.DisposeWith(disposable);
|
||||||
|
this.BindCommand(ViewModel, x => x.SortBySizeCommand, x => x.OrderBySizeButton)
|
||||||
|
.DisposeWith(disposable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user