Wow that was about as easy as pulling Trex teeth. Not sure why the RxApp scheduler isn't the same as the WPF scheduler

This commit is contained in:
Timothy Baldridge 2021-12-29 21:43:31 -07:00
parent cc8c40f803
commit 2215acf0e9
6 changed files with 96 additions and 56 deletions

View File

@ -4,7 +4,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wabbajack" xmlns:local="clr-namespace:Wabbajack"
ShutdownMode="OnExplicitShutdown" ShutdownMode="OnExplicitShutdown"
Startup="OnStartup"> Startup="OnStartup"
Exit="OnExit">
<Application.Resources> <Application.Resources>
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>

View File

@ -1,8 +1,14 @@
using System; using System;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Windows; using System.Windows;
using System.Windows.Threading;
using CefSharp.DevTools.Debugger;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using ReactiveUI;
using Splat;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack; using Wabbajack;
using Wabbajack.Services.OSIntegrated; using Wabbajack.Services.OSIntegrated;
@ -16,18 +22,27 @@ namespace Wabbajack
public partial class App public partial class App
{ {
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly IHost _host;
public App() public App()
{ {
var services = new ServiceCollection(); _host = Host.CreateDefaultBuilder(Array.Empty<string>())
.ConfigureLogging(c =>
{
c.ClearProviders();
})
.ConfigureServices((host, services) =>
{
ConfigureServices(services);
})
.Build();
var host = Host.CreateDefaultBuilder(Array.Empty<string>()) _serviceProvider = _host.Services;
//.ConfigureLogging(c => { c.ClearProviders(); })
.ConfigureServices((host, services) => { ConfigureServices(services); }).Build();
_serviceProvider = host.Services;
} }
private IServiceCollection ConfigureServices(IServiceCollection services) private IServiceCollection ConfigureServices(IServiceCollection services)
{ {
RxApp.MainThreadScheduler = new DispatcherScheduler(Dispatcher.CurrentDispatcher);
services.AddOSIntegrated(); services.AddOSIntegrated();
services.AddTransient<MainWindow>(); services.AddTransient<MainWindow>();
services.AddTransient<MainWindowVM>(); services.AddTransient<MainWindowVM>();
@ -40,13 +55,25 @@ namespace Wabbajack
services.AddTransient<ModeSelectionVM>(); services.AddTransient<ModeSelectionVM>();
services.AddTransient<ModListGalleryVM>(); services.AddTransient<ModListGalleryVM>();
return services; return services;
} }
private void OnStartup(object sender, StartupEventArgs e) private void OnStartup(object sender, StartupEventArgs e)
{ {
var mainWindow = _serviceProvider.GetRequiredService<MainWindow>(); RxApp.MainThreadScheduler.Schedule(0, (_, _) =>
mainWindow!.Show(); {
var mainWindow = _serviceProvider.GetRequiredService<MainWindow>();
mainWindow!.Show();
return Disposable.Empty;
});
}
private void OnExit(object sender, ExitEventArgs e)
{
using (_host)
{
_host.StopAsync();
}
base.OnExit(e);
} }
} }
} }

View File

@ -6,6 +6,7 @@ using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Threading;
using DynamicData; using DynamicData;
using DynamicData.Kernel; using DynamicData.Kernel;
using ReactiveUI; using ReactiveUI;

View File

@ -63,6 +63,9 @@ namespace Wabbajack
[Reactive] [Reactive]
public bool IsBroken { get; private set; } public bool IsBroken { get; private set; }
[Reactive]
public ModListStatus Status { get; set; }
[Reactive] [Reactive]
public bool IsDownloading { get; private set; } public bool IsDownloading { get; private set; }
@ -99,6 +102,8 @@ namespace Wabbajack
_wjClient = wjClient; _wjClient = wjClient;
Location = LauncherUpdater.CommonFolder.Value.Combine("downloaded_mod_lists", Metadata.Links.MachineURL).WithExtension(Ext.Wabbajack); Location = LauncherUpdater.CommonFolder.Value.Combine("downloaded_mod_lists", Metadata.Links.MachineURL).WithExtension(Ext.Wabbajack);
ModListTagList = new List<ModListTag>(); ModListTagList = new List<ModListTag>();
UpdateStatus().FireAndForget();
Metadata.Tags.ForEach(tag => Metadata.Tags.ForEach(tag =>
{ {
@ -224,6 +229,9 @@ namespace Wabbajack
private async Task Download() private async Task Download()
{ {
Status = ModListStatus.Downloading;
using var ll = LoadingLock.WithLoading();
var (progress, task) = _maintainer.DownloadModlist(Metadata); var (progress, task) = _maintainer.DownloadModlist(Metadata);
var dispose = progress var dispose = progress
.BindToStrict(this, vm => vm.ProgressPercent); .BindToStrict(this, vm => vm.ProgressPercent);
@ -231,7 +239,25 @@ namespace Wabbajack
await task; await task;
await _wjClient.SendMetric("downloading", Metadata.Title); await _wjClient.SendMetric("downloading", Metadata.Title);
await UpdateStatus();
dispose.Dispose(); dispose.Dispose();
} }
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
}
} }
} }

View File

@ -356,51 +356,13 @@
Height="40" Height="40"
Margin="5,0" Margin="5,0"
VerticalAlignment="Center"> VerticalAlignment="Center">
<Button.Style> <StackPanel x:Name="IconContainer">
<Style BasedOn="{StaticResource IconBareButtonStyle}" TargetType="Button"> <iconPacks:Material
<Setter Property="Content"> x:Name="ErrorIcon"
<Setter.Value> Width="20"
<iconPacks:Material Height="20"
Width="20" Kind="Exclamation" />
Height="20" </StackPanel>
Kind="Download" />
</Setter.Value>
</Setter>
<Setter Property="ToolTip" Value="Download modlist" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Exists}" Value="True" />
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Content">
<Setter.Value>
<iconPacks:Material
Width="20"
Height="20"
Kind="Play" />
</Setter.Value>
</Setter>
<Setter Property="ToolTip" Value="Install modlist" />
<Setter Property="Padding" Value="3,0,0,0" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<DataTrigger Binding="{Binding Error.Succeeded}" Value="False">
<Setter Property="Content">
<Setter.Value>
<iconPacks:Material
Width="20"
Height="20"
Kind="AlertCircle" />
</Setter.Value>
</Setter>
<Setter Property="ToolTip" Value="Error downloading modlist. Check logs and/or restart Wabbajack to try again." />
<Setter Property="Foreground" Value="{StaticResource ErrorBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button> </Button>
</Grid> </Grid>

View File

@ -1,6 +1,9 @@
using System.Reactive.Disposables; using System;
using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Windows; using System.Windows;
using System.Windows.Media.Media3D;
using MahApps.Metro.IconPacks;
using ReactiveUI; using ReactiveUI;
namespace Wabbajack namespace Wabbajack
@ -65,6 +68,26 @@ namespace Wabbajack
.BindTo(this, x => x.DownloadProgressBar.Value) .BindTo(this, x => x.DownloadProgressBar.Value)
.DisposeWith(disposables); .DisposeWith(disposables);
ViewModel.WhenAnyValue(x => x.Status)
.ObserveOnGuiThread()
.Subscribe(x =>
{
IconContainer.Children.Clear();
IconContainer.Children.Add(new PackIconMaterial
{
Width = 20,
Height = 20,
Kind = x switch
{
ModListMetadataVM.ModListStatus.Downloaded => PackIconMaterialKind.Play,
ModListMetadataVM.ModListStatus.Downloading => PackIconMaterialKind.Network,
ModListMetadataVM.ModListStatus.NotDownloaded => PackIconMaterialKind.Download,
_ => throw new ArgumentOutOfRangeException(nameof(x), x, null)
}
});
})
.DisposeWith(disposables);
/* /*
this.MarkAsNeeded<ModListTileView, ModListMetadataVM, bool>(this.ViewModel, x => x.IsBroken); this.MarkAsNeeded<ModListTileView, ModListMetadataVM, bool>(this.ViewModel, x => x.IsBroken);
this.MarkAsNeeded<ModListTileView, ModListMetadataVM, bool>(this.ViewModel, x => x.Exists); this.MarkAsNeeded<ModListTileView, ModListMetadataVM, bool>(this.ViewModel, x => x.Exists);