Skip to content

Commit 93ba1d0

Browse files
authored
Merge pull request #2740 from wabbajack-tools/publish_button_progress
Publish Button visual progress
2 parents ded3c23 + 0066473 commit 93ba1d0

File tree

7 files changed

+97
-53
lines changed

7 files changed

+97
-53
lines changed

Diff for: CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
### Changelog
22

3-
#### Version - 4.0.0.4 - Unreleased
3+
#### Version - 4.0.1.0 - Unreleased
44
* Fixed subfolders of profiles showing up under additional profiles within compiler settings
55
* Fixed Nexus login not taking cancellation token into account while waiting for authorization (closing the Nexus login prompt did not work)
66
* Added 2FA support for MEGA login, added some extra logging for MEGA logins
77
* Special thanks to [@erri120](https://www.github.com/erri120) who originally implemented part of this in Wabbajack and the MegaApiClient library 4 years ago, which made the change rather easy
88
* Added a warning for when WebView is not loading
9+
* Addd progress indicator to the publish button after compilation (thanks to [@JanuarySnow](https://www.github.com/JanuarySnow)))
910

1011
#### Version - 4.0.0.3 - 3/20/2025
1112
* Fixed the open logs folder button not actually opening the logs folder on a failed installation

Diff for: Wabbajack.App.Wpf/ViewModels/Compiler/CompilerMainVM.cs

+36-10
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ public class CompilerMainVM : BaseCompilerVM, ICanGetHelpVM, ICpuStatusVM
5252
public ICommand OpenFolderCommand { get; }
5353
public ICommand PublishCommand { get; }
5454

55+
[Reactive] public bool IsPublishing { get; set; }
56+
[Reactive] public Percent PublishingPercentage { get; set; } = Percent.One;
5557
[Reactive] public CompilerState State { get; set; }
58+
5659
public bool Cancelling { get; private set; }
5760

5861
public ReadOnlyObservableCollection<CPUDisplayVM> StatusList => _resourceMonitor.Tasks;
@@ -90,7 +93,11 @@ public CompilerMainVM(ILogger<CompilerMainVM> logger, DTOSerializer dtos, Settin
9093
CancelCommand = ReactiveCommand.Create(CancelCompilation);
9194
OpenLogCommand = ReactiveCommand.Create(OpenLog);
9295
OpenFolderCommand = ReactiveCommand.Create(OpenFolder);
93-
PublishCommand = ReactiveCommand.Create(Publish);
96+
PublishCommand = ReactiveCommand.Create(Publish,
97+
this.WhenAnyValue(vm => vm.State,
98+
vm => vm.IsPublishing,
99+
(state, isPublishing) => !isPublishing && state == CompilerState.Completed));
100+
94101
ProgressPercent = Percent.Zero;
95102

96103
this.WhenActivated(disposables =>
@@ -136,14 +143,33 @@ private void OpenLog()
136143

137144
private async Task Publish()
138145
{
139-
_logger.LogInformation("Running preflight checks before publishing list");
140-
bool readyForPublish = await RunPreflightChecks(CancellationToken.None);
141-
if (!readyForPublish) return;
142-
143-
_logger.LogInformation("Publishing list with machineURL {machineURL}, version {version}, output {output}", Settings.MachineUrl, Settings.Version, Settings.OutputFile);
144-
var downloadMetadata = _dtos.Deserialize<DownloadMetadata>(
145-
await Settings.OutputFile.WithExtension(Ext.Meta).WithExtension(Ext.Json).ReadAllTextAsync())!;
146-
await _wjClient.PublishModlist(Settings.MachineUrl, Version.Parse(Settings.Version), Settings.OutputFile, downloadMetadata);
146+
try
147+
{
148+
IsPublishing = true;
149+
PublishingPercentage = Percent.Zero;
150+
151+
_logger.LogInformation("Running preflight checks before publishing list");
152+
bool readyForPublish = await RunPreflightChecks(CancellationToken.None);
153+
if (!readyForPublish) return;
154+
155+
_logger.LogInformation("Publishing list with machineURL {machineURL}, version {version}, output {output}",
156+
Settings.MachineUrl, Settings.Version, Settings.OutputFile);
157+
158+
var downloadMetadata = _dtos.Deserialize<DownloadMetadata>(
159+
await Settings.OutputFile.WithExtension(Ext.Meta).WithExtension(Ext.Json).ReadAllTextAsync())!;
160+
var (progress, publishTask) = await _wjClient.PublishModlist(Settings.MachineUrl, Version.Parse(Settings.Version), Settings.OutputFile, downloadMetadata);
161+
using var progressSubscription = progress.Subscribe(p => PublishingPercentage = p.PercentDone);
162+
await publishTask;
163+
}
164+
catch (Exception ex)
165+
{
166+
_logger.LogError("While publishing: {ex}", ex);
167+
}
168+
finally
169+
{
170+
IsPublishing = false;
171+
PublishingPercentage = Percent.One;
172+
}
147173
}
148174

149175
private void OpenFolder() => UIUtils.OpenFolderAndSelectFile(Settings.OutputFile);
@@ -312,7 +338,7 @@ private async Task<bool> RunPreflightChecks(CancellationToken token)
312338
return false;
313339
}
314340

315-
if (!Version.TryParse(Settings.Version, out var version))
341+
if (!System.Version.TryParse(Settings.Version, out var version))
316342
{
317343
_logger.LogError("Preflight Check failed, version {Version} was not valid", Settings.Version);
318344
return false;

Diff for: Wabbajack.App.Wpf/Views/Common/WJButton.xaml.cs

+4-7
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
using System.Reactive.Linq;
55
using System.Windows;
66
using System;
7-
using System.Windows.Input;
87
using Wabbajack.RateLimiter;
98
using System.Windows.Media;
10-
using ReactiveUI.Fody.Helpers;
119
using System.Windows.Controls;
1210
using System.ComponentModel;
1311

@@ -137,18 +135,17 @@ public WJButton()
137135
.DisposeWith(dispose);
138136

139137
this.WhenAnyValue(x => x.ProgressPercentage)
138+
.ObserveOnGuiThread()
140139
.Subscribe(percent =>
141140
{
142141
if (ButtonStyle != ButtonStyle.Progress) return;
143142
if (percent == Percent.One)
144143
{
144+
this.ClearValue(BackgroundProperty);
145+
ButtonTextBlock.ClearValue(ForegroundProperty);
146+
ButtonSymbolIcon.ClearValue(ForegroundProperty);
145147
Style = (Style)Application.Current.Resources["WJColorButtonStyle"];
146148
}
147-
else if (percent == Percent.Zero)
148-
{
149-
Background = new SolidColorBrush((Color)Application.Current.Resources["ComplementaryPrimary08"]);
150-
Foreground = new SolidColorBrush((Color)Application.Current.Resources["ForegroundColor"]);
151-
}
152149
else
153150
{
154151
var bgBrush = new LinearGradientBrush();

Diff for: Wabbajack.App.Wpf/Views/Compiler/CompilerMainView.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
</Grid.ColumnDefinitions>
6868
<local:WJButton x:Name="OpenLogButton" Text="Open Log" Icon="DocumentText" HorizontalAlignment="Left" />
6969
<local:WJButton x:Name="OpenFolderButton" Text="Open in File Explorer" Icon="Folder" HorizontalAlignment="Right" Grid.Column="2" ButtonStyle="Color" />
70-
<local:WJButton x:Name="PublishButton" Text="Publish Modlist" Icon="CloudArrowUp" HorizontalAlignment="Right" Grid.Column="4" ButtonStyle="Color" />
70+
<local:WJButton x:Name="PublishButton" Text="Publish Modlist" Icon="CloudArrowUp" HorizontalAlignment="Right" Grid.Column="4" ButtonStyle="Progress" />
7171
</Grid>
7272
</Grid>
7373
</rxui:ReactiveUserControl>

Diff for: Wabbajack.App.Wpf/Views/Compiler/CompilerMainView.xaml.cs

+14-5
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ namespace Wabbajack;
1717
/// </summary>
1818
public partial class CompilerMainView : ReactiveUserControl<CompilerMainVM>
1919
{
20+
private bool _ClickedPublish = false;
21+
2022
public CompilerMainView()
2123
{
2224
InitializeComponent();
2325

2426
this.WhenActivated(disposables =>
2527
{
28+
_ClickedPublish = false;
2629
ViewModel.WhenAny(vm => vm.Settings.ModListImage)
2730
.Where(i => i.FileExists())
2831
.Select(i => (UIUtils.TryGetBitmapImageFromFile(i, out var img), img))
@@ -88,11 +91,6 @@ public CompilerMainView()
8891
.BindToStrict(this, view => view.OpenFolderButton.IsEnabled)
8992
.DisposeWith(disposables);
9093

91-
ViewModel.WhenAny(vm => vm.State)
92-
.Select(s => s == CompilerState.Completed)
93-
.BindToStrict(this, view => view.PublishButton.IsEnabled)
94-
.DisposeWith(disposables);
95-
9694
ViewModel.WhenAny(vm => vm.State)
9795
.Select(s => s == CompilerState.Completed ? Visibility.Visible : Visibility.Hidden)
9896
.BindToStrict(this, view => view.CompiledImage.Visibility)
@@ -128,6 +126,17 @@ public CompilerMainView()
128126

129127
this.BindCommand(ViewModel, x => x.PublishCommand, x => x.PublishButton)
130128
.DisposeWith(disposables);
129+
130+
ViewModel.WhenAnyValue(vm => vm.PublishingPercentage)
131+
.ObserveOnGuiThread()
132+
.Subscribe(pct =>
133+
{
134+
if (pct != RateLimiter.Percent.One) _ClickedPublish = true;
135+
PublishButton.ProgressPercentage = pct;
136+
PublishButton.Text = (pct.Value >= 0 && pct.Value < 1) ? "Publishing..." : _ClickedPublish ? "Publish Completed" : "Publish Modlist";
137+
})
138+
.DisposeWith(disposables);
139+
131140
});
132141
}
133142
}

Diff for: Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
<Platforms>x64</Platforms>
88
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
99
<Version>$(VERSION)</Version>
10-
<AssemblyVersion>$(VERSION)</AssemblyVersion>
11-
<FileVersion>$(VERSION)</FileVersion>
10+
<AssemblyVersion>4.0.0.0</AssemblyVersion>
11+
<FileVersion>4.0.0.0</FileVersion>
1212
<Copyright>Copyright © 2019-2024</Copyright>
1313
<Description>An automated ModList installer</Description>
1414
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

Diff for: Wabbajack.Networking.WabbajackClientApi/Client.cs

+38-27
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Net;
77
using System.Net.Http;
88
using System.Net.Http.Json;
9+
using System.Reactive.Linq;
910
using System.Reactive.Subjects;
1011
using System.Text;
1112
using System.Text.Json;
@@ -434,7 +435,7 @@ public async Task DeleteMirror(Hash hash)
434435
var apiKey = (await _token.Get())!.AuthorKey;
435436
var report = new Subject<(Percent PercentDone, string Message)>();
436437

437-
var tsk = Task.Run<Uri>(async () =>
438+
var tsk = Task.Run(async () =>
438439
{
439440
report.OnNext((Percent.Zero, "Generating File Definition"));
440441
var definition = await GenerateFileDefinition(path);
@@ -479,6 +480,7 @@ await CircuitBreaker.WithAutoRetryAllAsync(_logger, async () =>
479480
});
480481

481482
report.OnNext((Percent.Zero, "Finalizing upload"));
483+
_logger.LogInformation("Finalizing upload");
482484
return await CircuitBreaker.WithAutoRetryAllAsync(_logger, async () =>
483485
{
484486
var msg = await MakeMessage(HttpMethod.Put,
@@ -542,53 +544,62 @@ public async Task<bool> ProxyHas(Uri uri)
542544

543545
public async Task<IReadOnlyList<string>> GetMyModlists(CancellationToken token)
544546
{
547+
return ["tr4wzified/trawzifieds_helper"];
548+
545549
var msg = await MakeMessage(HttpMethod.Get, new Uri($"{_configuration.BuildServerUrl}author_controls/lists"));
546550
using var response = await _client.SendAsync(msg, token);
547551
HttpException.ThrowOnFailure(response);
548552
return (await _dtos.DeserializeAsync<string[]>(await response.Content.ReadAsStreamAsync(token), token))!;
549553
}
550554

551-
public async Task PublishModlist(string namespacedName, Version version, AbsolutePath modList, DownloadMetadata metadata)
555+
public async Task<(IObservable<(Percent PercentDone, string Message)> Progress, Task PublishTask)> PublishModlist(
556+
string namespacedName, Version version, AbsolutePath modList, DownloadMetadata metadata)
552557
{
553558
var pair = namespacedName.Split("/");
554559
var wjRepoName = pair[0];
555560
var machineUrl = pair[1];
556561

557562
var repoUrl = (await LoadRepositories())[wjRepoName];
558-
559563
var decomposed = repoUrl.LocalPath.Split("/");
560564
var owner = decomposed[1];
561565
var repoName = decomposed[2];
562566
var path = string.Join("/", decomposed[4..]);
563-
564-
_logger.LogInformation("Uploading modlist {MachineUrl}", namespacedName);
565-
567+
566568
var (progress, uploadTask) = await UploadAuthorFile(modList);
567-
progress.Subscribe(x => _logger.LogInformation(x.Message));
568-
var downloadUrl = await uploadTask;
569569

570-
_logger.LogInformation("Publishing modlist {MachineUrl}", namespacedName);
571-
572-
var creds = new Credentials((await _token.Get())!.AuthorKey);
573-
var ghClient = new GitHubClient(new ProductHeaderValue("wabbajack")) {Credentials = creds};
570+
// Usually the GitHub publish will take basically no time at all compared to the upload so just ignore progress percentage here
571+
var publishTask = Task.Run(async () =>
572+
{
573+
var downloadUrl = await uploadTask;
574574

575-
var oldData =
576-
(await ghClient.Repository.Content.GetAllContents(owner, repoName, path))
577-
.First();
578-
var oldContent = _dtos.Deserialize<ModlistMetadata[]>(oldData.Content);
579-
var list = oldContent.First(c => c.Links.MachineURL == machineUrl);
580-
list.Version = version;
581-
list.DownloadMetadata = metadata;
582-
list.Links.Download = downloadUrl.ToString();
583-
list.DateUpdated = DateTime.UtcNow;
575+
_logger.LogInformation("Publishing modlist {MachineUrl}", namespacedName);
584576

577+
var creds = new Credentials((await _token.Get())!.AuthorKey);
578+
var ghClient = new GitHubClient(new ProductHeaderValue("wabbajack"))
579+
{
580+
Credentials = creds
581+
};
585582

586-
var newContent = _dtos.Serialize(oldContent, true);
587-
// the website requires all names be in lowercase;
588-
newContent = GameRegistry.Games.Keys.Aggregate(newContent,
589-
(current, g) => current.Replace($"\"game\": \"{g}\",", $"\"game\": \"{g.ToString().ToLower()}\","));
583+
var oldData =
584+
(await ghClient.Repository.Content.GetAllContents(owner, repoName, path))
585+
.First();
586+
var oldContent = _dtos.Deserialize<ModlistMetadata[]>(oldData.Content);
587+
var list = oldContent.First(c => c.Links.MachineURL == machineUrl);
588+
list.Version = version;
589+
list.DownloadMetadata = metadata;
590+
list.Links.Download = downloadUrl.ToString();
591+
list.DateUpdated = DateTime.UtcNow;
592+
593+
var newContent = _dtos.Serialize(oldContent, true);
594+
// Ensure game names are lowercase
595+
newContent = GameRegistry.Games.Keys.Aggregate(newContent,
596+
(current, g) => current.Replace($"\"game\": \"{g}\",", $"\"game\": \"{g.ToString().ToLower()}\","));
597+
598+
var updateRequest = new UpdateFileRequest($"New release of {machineUrl}", newContent, oldData.Sha);
599+
await ghClient.Repository.Content.UpdateFile(owner, repoName, path, updateRequest);
600+
});
590601

591-
var updateRequest = new UpdateFileRequest($"New release of {machineUrl}", newContent, oldData.Sha);
592-
await ghClient.Repository.Content.UpdateFile(owner, repoName, path, updateRequest);
602+
return (progress, publishTask);
593603
}
604+
594605
}

0 commit comments

Comments
 (0)