mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Rework gallery loading, and VM creation
This commit is contained in:
parent
12bb5fe083
commit
bd71de5883
@ -37,6 +37,8 @@ namespace Wabbajack
|
||||
services.AddSingleton<MainSettings>();
|
||||
services.AddTransient<CompilerVM>();
|
||||
services.AddTransient<InstallerVM>();
|
||||
services.AddTransient<ModeSelectionVM>();
|
||||
services.AddTransient<ModListGalleryVM>();
|
||||
|
||||
|
||||
return services;
|
||||
|
11
Wabbajack.App.Wpf/Messages/NavigateBack.cs
Normal file
11
Wabbajack.App.Wpf/Messages/NavigateBack.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Wabbajack.Messages;
|
||||
|
||||
public class NavigateBack
|
||||
{
|
||||
public static void Send()
|
||||
{
|
||||
MessageBus.Current.SendMessage(new NavigateBack());
|
||||
}
|
||||
}
|
21
Wabbajack.App.Wpf/Messages/NavigateTo.cs
Normal file
21
Wabbajack.App.Wpf/Messages/NavigateTo.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using ReactiveUI;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack.Messages;
|
||||
|
||||
public class NavigateTo
|
||||
{
|
||||
|
||||
public ViewModel ViewModel { get; }
|
||||
private NavigateTo(ViewModel vm)
|
||||
{
|
||||
ViewModel = vm;
|
||||
}
|
||||
|
||||
public static void Send<T>(T vm)
|
||||
where T : ViewModel
|
||||
{
|
||||
MessageBus.Current.SendMessage(new NavigateTo(vm));
|
||||
}
|
||||
|
||||
}
|
29
Wabbajack.App.Wpf/Messages/NavigateToGlobal.cs
Normal file
29
Wabbajack.App.Wpf/Messages/NavigateToGlobal.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Wabbajack.Messages;
|
||||
|
||||
public class NavigateToGlobal
|
||||
{
|
||||
public enum ScreenType
|
||||
{
|
||||
ModeSelectionView,
|
||||
ModListGallery,
|
||||
Installer,
|
||||
Settings,
|
||||
Compiler,
|
||||
ModListContents
|
||||
}
|
||||
|
||||
public ScreenType Screen { get; }
|
||||
|
||||
private NavigateToGlobal(ScreenType screen)
|
||||
{
|
||||
Screen = screen;
|
||||
}
|
||||
|
||||
public static void Send(ScreenType screen)
|
||||
{
|
||||
MessageBus.Current.SendMessage(new NavigateToGlobal(screen));
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@ -7,6 +8,7 @@ using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Messages;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
@ -24,27 +26,30 @@ namespace Wabbajack
|
||||
[Reactive]
|
||||
public ViewModel NavigateBackTarget { get; set; }
|
||||
public ReactiveCommand<Unit, Unit> BackCommand { get; protected set; }
|
||||
|
||||
protected ObservableAsPropertyHelper<bool> _IsActive;
|
||||
public bool IsActive => _IsActive.Value;
|
||||
|
||||
[Reactive]
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public Subject<bool> IsBackEnabledSubject { get; } = new Subject<bool>();
|
||||
public IObservable<bool> IsBackEnabled { get; }
|
||||
|
||||
public BackNavigatingVM(ILogger logger, MainWindowVM mainWindowVM)
|
||||
public BackNavigatingVM(ILogger logger)
|
||||
{
|
||||
IsBackEnabled = IsBackEnabledSubject.StartWith(true);
|
||||
BackCommand = ReactiveCommand.Create(
|
||||
execute: () => logger.CatchAndLog(() =>
|
||||
{
|
||||
mainWindowVM.NavigateTo(NavigateBackTarget);
|
||||
NavigateBack.Send();
|
||||
Unload();
|
||||
}),
|
||||
canExecute: this.ConstructCanNavigateBack()
|
||||
.ObserveOnGuiThread());
|
||||
|
||||
_IsActive = this.ConstructIsActive(mainWindowVM)
|
||||
.ToGuiProperty(this, nameof(IsActive));
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
IsActive = true;
|
||||
Disposable.Create(() => IsActive = false).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public virtual void Unload()
|
||||
@ -60,7 +65,7 @@ namespace Wabbajack
|
||||
.CombineLatest(vm.IsBackEnabled)
|
||||
.Select(x => x.First != null && x.Second);
|
||||
}
|
||||
|
||||
|
||||
public static IObservable<bool> ConstructIsActive(this IBackNavigatingVM vm, MainWindowVM mwvm)
|
||||
{
|
||||
return mwvm.WhenAny(x => x.ActivePane)
|
||||
|
@ -13,6 +13,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.Compiler;
|
||||
using Wabbajack.Lib.Extensions;
|
||||
using Wabbajack.Lib.Interventions;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.RateLimiter;
|
||||
|
||||
namespace Wabbajack
|
||||
@ -64,7 +65,7 @@ namespace Wabbajack
|
||||
private readonly ObservableAsPropertyHelper<(int CurrentCPUs, int DesiredCPUs)> _CurrentCpuCount;
|
||||
public (int CurrentCPUs, int DesiredCPUs) CurrentCpuCount => _CurrentCpuCount.Value;
|
||||
|
||||
public CompilerVM(ILogger<CompilerVM> logger, MainWindowVM mainWindowVM) : base(logger, mainWindowVM)
|
||||
public CompilerVM(ILogger<CompilerVM> logger, MainWindowVM mainWindowVM) : base(logger)
|
||||
{
|
||||
MWVM = mainWindowVM;
|
||||
|
||||
@ -133,7 +134,7 @@ namespace Wabbajack
|
||||
BackCommand = ReactiveCommand.Create(
|
||||
execute: () =>
|
||||
{
|
||||
mainWindowVM.NavigateTo(mainWindowVM.ModeSelectionVM);
|
||||
NavigateToGlobal.Send(NavigateToGlobal.ScreenType.ModeSelectionView);
|
||||
StartedCompilation = false;
|
||||
Completed = null;
|
||||
},
|
||||
|
@ -1,9 +1,13 @@
|
||||
using System;
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
@ -17,6 +21,7 @@ using Wabbajack.DTOs;
|
||||
using Wabbajack.Hashing.xxHash64;
|
||||
using Wabbajack.Lib.Extensions;
|
||||
using Wabbajack.Networking.WabbajackClientApi;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
using Wabbajack.Services.OSIntegrated.Services;
|
||||
|
||||
namespace Wabbajack
|
||||
@ -24,68 +29,48 @@ namespace Wabbajack
|
||||
public class ModListGalleryVM : BackNavigatingVM
|
||||
{
|
||||
public MainWindowVM MWVM { get; }
|
||||
|
||||
public ObservableCollectionExtended<ModListMetadataVM> ModLists { get; } = new ObservableCollectionExtended<ModListMetadataVM>();
|
||||
|
||||
private readonly SourceCache<ModListMetadataVM, string> _modLists = new(x => x.Metadata.Links.MachineURL);
|
||||
public ReadOnlyObservableCollection<ModListMetadataVM> _filteredModLists;
|
||||
public ReadOnlyObservableCollection<ModListMetadataVM> ModLists => _filteredModLists;
|
||||
|
||||
private const string ALL_GAME_TYPE = "All";
|
||||
|
||||
[Reactive]
|
||||
public IErrorResponse Error { get; set; }
|
||||
[Reactive] public IErrorResponse Error { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string Search { get; set; }
|
||||
[Reactive] public string Search { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool OnlyInstalled { get; set; }
|
||||
[Reactive] public bool OnlyInstalled { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool ShowNSFW { get; set; }
|
||||
[Reactive] public bool ShowNSFW { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool ShowUtilityLists { get; set; }
|
||||
[Reactive] public bool ShowUtilityLists { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string GameType { get; set; }
|
||||
[Reactive] public string GameType { get; set; }
|
||||
|
||||
public List<string> GameTypeEntries { get { return GetGameTypeEntries(); } }
|
||||
public List<string> GameTypeEntries => GetGameTypeEntries();
|
||||
|
||||
private readonly ObservableAsPropertyHelper<bool> _Loaded;
|
||||
private ObservableAsPropertyHelper<bool> _Loaded;
|
||||
private readonly Client _wjClient;
|
||||
private readonly ILogger<ModListGalleryVM> _logger;
|
||||
private readonly GameLocator _locator;
|
||||
private readonly ModListDownloadMaintainer _maintainer;
|
||||
|
||||
private FiltersSettings settings => MWVM.Settings.Filters;
|
||||
private FiltersSettings settings { get; set; } = new();
|
||||
|
||||
public bool Loaded => _Loaded.Value;
|
||||
|
||||
public ICommand ClearFiltersCommand { get; }
|
||||
public ICommand ClearFiltersCommand { get; set; }
|
||||
|
||||
public ModListGalleryVM(ILogger<ModListGalleryVM> logger, MainWindowVM mainWindowVM, Client wjClient,
|
||||
GameLocator locator, IServiceProvider provider)
|
||||
: base(logger, mainWindowVM)
|
||||
public ModListGalleryVM(ILogger<ModListGalleryVM> logger, Client wjClient,
|
||||
GameLocator locator, SettingsManager settingsManager, ModListDownloadMaintainer maintainer)
|
||||
: base(logger)
|
||||
{
|
||||
MWVM = mainWindowVM;
|
||||
_wjClient = wjClient;
|
||||
_logger = logger;
|
||||
_locator = locator;
|
||||
|
||||
// load persistent filter settings
|
||||
if (settings.IsPersistent)
|
||||
{
|
||||
GameType = !string.IsNullOrEmpty(settings.Game) ? settings.Game : ALL_GAME_TYPE;
|
||||
ShowNSFW = settings.ShowNSFW;
|
||||
ShowUtilityLists = settings.ShowUtilityLists;
|
||||
OnlyInstalled = settings.OnlyInstalled;
|
||||
Search = settings.Search;
|
||||
}
|
||||
else
|
||||
GameType = ALL_GAME_TYPE;
|
||||
|
||||
// subscribe to save signal
|
||||
MWVM.Settings.SaveSignal
|
||||
.Subscribe(_ => UpdateFiltersSettings())
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
|
||||
_maintainer = maintainer;
|
||||
|
||||
ClearFiltersCommand = ReactiveCommand.Create(
|
||||
() =>
|
||||
{
|
||||
@ -97,101 +82,16 @@ namespace Wabbajack
|
||||
});
|
||||
|
||||
|
||||
this.WhenAny(x => x.OnlyInstalled)
|
||||
.Subscribe(val =>
|
||||
{
|
||||
if(val)
|
||||
GameType = ALL_GAME_TYPE;
|
||||
})
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
var sourceList = Observable.Return(Unit.Default)
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.SelectMany(async _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Error = null;
|
||||
var list = await _wjClient.LoadLists();
|
||||
Error = ErrorResponse.Success;
|
||||
return list
|
||||
.AsObservableChangeSet(x => x.DownloadMetadata?.Hash ?? default);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "While Loading Lists");
|
||||
Error = ErrorResponse.Fail(ex);
|
||||
return Observable.Empty<IChangeSet<ModlistMetadata, Hash>>();
|
||||
}
|
||||
})
|
||||
// Unsubscribe and release when not active
|
||||
.FlowSwitch(
|
||||
this.WhenAny(x => x.IsActive),
|
||||
valueWhenOff: Observable.Return(ChangeSet<ModlistMetadata, Hash>.Empty))
|
||||
.Switch()
|
||||
.RefCount();
|
||||
|
||||
_Loaded = sourceList.CollectionCount()
|
||||
.Select(c => c > 0)
|
||||
.ToProperty(this, nameof(Loaded));
|
||||
|
||||
// Convert to VM and bind to resulting list
|
||||
sourceList
|
||||
.ObserveOnGuiThread()
|
||||
.Transform(m => new ModListMetadataVM(provider.GetRequiredService<ILogger<ModListMetadataVM>>(),this, m,
|
||||
provider.GetRequiredService<ModListDownloadMaintainer>(), provider.GetRequiredService<Client>()))
|
||||
.DisposeMany()
|
||||
// Filter only installed
|
||||
.Filter(this.WhenAny(x => x.OnlyInstalled)
|
||||
.Select<bool, Func<ModListMetadataVM, bool>>(onlyInstalled => (vm) =>
|
||||
{
|
||||
if (!onlyInstalled) return true;
|
||||
if (!GameRegistry.Games.TryGetValue(vm.Metadata.Game, out var gameMeta)) return false;
|
||||
return _locator.IsInstalled(gameMeta.Game);
|
||||
}))
|
||||
// Filter on search box
|
||||
.Filter(this.WhenAny(x => x.Search)
|
||||
.Debounce(TimeSpan.FromMilliseconds(150), RxApp.MainThreadScheduler)
|
||||
.Select<string, Func<ModListMetadataVM, bool>>(search => (vm) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(search)) return true;
|
||||
return vm.Metadata.Title.ContainsCaseInsensitive(search) || vm.Metadata.tags.Any(t => t.ContainsCaseInsensitive(search));
|
||||
}))
|
||||
.Filter(this.WhenAny(x => x.ShowNSFW)
|
||||
.Select<bool, Func<ModListMetadataVM, bool>>(showNSFW => vm =>
|
||||
{
|
||||
if (!vm.Metadata.NSFW) return true;
|
||||
return vm.Metadata.NSFW && showNSFW;
|
||||
}))
|
||||
.Filter(this.WhenAny(x => x.ShowUtilityLists)
|
||||
.Select<bool, Func<ModListMetadataVM, bool>>(showUtilityLists => vm => showUtilityLists ? vm.Metadata.UtilityList : !vm.Metadata.UtilityList))
|
||||
// Filter by Game
|
||||
.Filter(this.WhenAny(x => x.GameType)
|
||||
.Debounce(TimeSpan.FromMilliseconds(150), RxApp.MainThreadScheduler)
|
||||
.Select<string, Func<ModListMetadataVM, bool>>(GameType => (vm) =>
|
||||
{
|
||||
if (GameType == ALL_GAME_TYPE)
|
||||
return true;
|
||||
if (string.IsNullOrEmpty(GameType))
|
||||
return false;
|
||||
|
||||
return GameType == vm.Metadata.Game.GetDescription<Game>().ToString();
|
||||
|
||||
}))
|
||||
.Bind(ModLists)
|
||||
.Subscribe()
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
// Extra GC when navigating away, just to immediately clean up modlist metadata
|
||||
this.WhenAny(x => x.IsActive)
|
||||
.Where(x => !x)
|
||||
.Skip(1)
|
||||
.Delay(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler)
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
GC.Collect();
|
||||
})
|
||||
.DisposeWith(CompositeDisposable);
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
var _ = LoadModLists();
|
||||
|
||||
_modLists.Connect()
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Bind(out _filteredModLists)
|
||||
.Subscribe()
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public override void Unload()
|
||||
@ -199,9 +99,30 @@ namespace Wabbajack
|
||||
Error = null;
|
||||
}
|
||||
|
||||
private async Task LoadModLists()
|
||||
{
|
||||
using var ll = LoadingLock.WithLoading();
|
||||
try
|
||||
{
|
||||
var modLists = await _wjClient.LoadLists();
|
||||
_modLists.Edit(e =>
|
||||
{
|
||||
e.Clear();
|
||||
e.AddOrUpdate(modLists.Select(m =>
|
||||
new ModListMetadataVM(_logger, this, m, _maintainer, _wjClient)));
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "While loading lists");
|
||||
ll.Fail();
|
||||
}
|
||||
ll.Succeed();
|
||||
}
|
||||
|
||||
private List<string> GetGameTypeEntries()
|
||||
{
|
||||
List<string> gameEntries = new List<string> { ALL_GAME_TYPE };
|
||||
List<string> gameEntries = new List<string> {ALL_GAME_TYPE};
|
||||
gameEntries.AddRange(GameRegistry.Games.Values.Select(gameType => gameType.HumanFriendlyGameName));
|
||||
gameEntries.Sort();
|
||||
return gameEntries;
|
||||
@ -216,4 +137,4 @@ namespace Wabbajack
|
||||
settings.OnlyInstalled = OnlyInstalled;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ using Wabbajack.DTOs;
|
||||
using Wabbajack.DTOs.ServerResponses;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.Extensions;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.Networking.WabbajackClientApi;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.Paths.IO;
|
||||
@ -126,7 +127,7 @@ namespace Wabbajack
|
||||
ArchiveStatus = a.Status,
|
||||
IsFailing = a.Status != ArchiveStatus.InValid
|
||||
}));
|
||||
_parent.MWVM.NavigateTo(_parent.MWVM.ModListContentsVM.Value);
|
||||
NavigateToGlobal.Send(NavigateToGlobal.ScreenType.ModListContents);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -15,6 +15,7 @@ using Microsoft.WindowsAPICodePack.Shell;
|
||||
using Wabbajack.DTOs.JsonConverters;
|
||||
using Wabbajack.Lib.Extensions;
|
||||
using Wabbajack.Lib.Interventions;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.RateLimiter;
|
||||
using Wabbajack.View_Models;
|
||||
using Wabbajack.Paths.IO;
|
||||
@ -98,7 +99,7 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
|
||||
public ReactiveCommand<Unit, Unit> GoToInstallCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> BeginCommand { get; }
|
||||
|
||||
public InstallerVM(ILogger<InstallerVM> logger, MainWindowVM mainWindowVM, IServiceProvider serviceProvider) : base(logger, mainWindowVM)
|
||||
public InstallerVM(ILogger<InstallerVM> logger, MainWindowVM mainWindowVM, IServiceProvider serviceProvider) : base(logger)
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
@ -162,10 +163,7 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
|
||||
MWVM.Settings.Installer.LastInstalledListLocation = ModListLocation.TargetPath;
|
||||
})
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
_IsActive = this.ConstructIsActive(MWVM)
|
||||
.ToGuiProperty(this, nameof(IsActive));
|
||||
|
||||
|
||||
// Active path represents the path to currently have loaded
|
||||
// If we're not actively showing, then "unload" the active path
|
||||
var activePath = Observable.CombineLatest(
|
||||
@ -239,7 +237,7 @@ public class InstallerVM : BackNavigatingVM, IBackNavigatingVM, ICpuStatusVM
|
||||
{
|
||||
StartedInstallation = false;
|
||||
Completed = null;
|
||||
mainWindowVM.NavigateTo(mainWindowVM.ModeSelectionVM);
|
||||
NavigateToGlobal.Send(NavigateToGlobal.ScreenType.ModeSelectionView);
|
||||
},
|
||||
canExecute: Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Installing)
|
||||
|
@ -3,6 +3,7 @@ using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
@ -14,6 +15,7 @@ using Wabbajack.Common;
|
||||
using Wabbajack.Downloaders.GameFile;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.Interventions;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.Networking.WabbajackClientApi;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.View_Models;
|
||||
@ -38,7 +40,7 @@ namespace Wabbajack
|
||||
public readonly Lazy<CompilerVM> Compiler;
|
||||
public readonly Lazy<InstallerVM> Installer;
|
||||
public readonly Lazy<SettingsVM> SettingsPane;
|
||||
public readonly Lazy<ModListGalleryVM> Gallery;
|
||||
public readonly ModListGalleryVM Gallery;
|
||||
public readonly ModeSelectionVM ModeSelectionVM;
|
||||
public readonly Lazy<ModListContentsVM> ModListContentsVM;
|
||||
public readonly UserInterventionHandlers UserInterventionHandlers;
|
||||
@ -55,7 +57,7 @@ namespace Wabbajack
|
||||
public bool UpdateAvailable { get; private set; }
|
||||
|
||||
public MainWindowVM(ILogger<MainWindowVM> logger, MainSettings settings, Client wjClient,
|
||||
IServiceProvider serviceProvider)
|
||||
IServiceProvider serviceProvider, ModeSelectionVM modeSelectionVM, ModListGalleryVM modListGalleryVM)
|
||||
{
|
||||
_logger = logger;
|
||||
_wjClient = wjClient;
|
||||
@ -64,12 +66,15 @@ namespace Wabbajack
|
||||
Installer = new Lazy<InstallerVM>(() => new InstallerVM(serviceProvider.GetRequiredService<ILogger<InstallerVM>>(), this, serviceProvider));
|
||||
Compiler = new Lazy<CompilerVM>(() => new CompilerVM(serviceProvider.GetRequiredService<ILogger<CompilerVM>>(), this));
|
||||
SettingsPane = new Lazy<SettingsVM>(() => new SettingsVM(serviceProvider.GetRequiredService<ILogger<SettingsVM>>(), this, serviceProvider));
|
||||
Gallery = new Lazy<ModListGalleryVM>(() => new ModListGalleryVM(serviceProvider.GetRequiredService<ILogger<ModListGalleryVM>>(), this,
|
||||
serviceProvider.GetRequiredService<Client>(), serviceProvider.GetRequiredService<GameLocator>(), serviceProvider));
|
||||
ModeSelectionVM = new ModeSelectionVM(this);
|
||||
Gallery = modListGalleryVM;
|
||||
ModeSelectionVM = modeSelectionVM;
|
||||
ModListContentsVM = new Lazy<ModListContentsVM>(() => new ModListContentsVM(serviceProvider.GetRequiredService<ILogger<ModListContentsVM>>(), this));
|
||||
UserInterventionHandlers = new UserInterventionHandlers(serviceProvider.GetRequiredService<ILogger<UserInterventionHandlers>>(), this);
|
||||
|
||||
MessageBus.Current.Listen<NavigateToGlobal>()
|
||||
.Subscribe(m => HandleNavigateTo(m.Screen))
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
// Set up logging
|
||||
/* TODO
|
||||
Utils.LogMessages
|
||||
@ -116,12 +121,12 @@ namespace Wabbajack
|
||||
if (IsStartingFromModlist(out var path))
|
||||
{
|
||||
Installer.Value.ModListLocation.TargetPath = path;
|
||||
NavigateTo(Installer.Value);
|
||||
NavigateToGlobal.Send(NavigateToGlobal.ScreenType.Installer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start on mode selection
|
||||
NavigateTo(ModeSelectionVM);
|
||||
NavigateToGlobal.Send(NavigateToGlobal.ScreenType.ModeSelectionView);
|
||||
}
|
||||
|
||||
try
|
||||
@ -147,7 +152,19 @@ namespace Wabbajack
|
||||
OpenSettingsCommand = ReactiveCommand.Create(
|
||||
canExecute: this.WhenAny(x => x.ActivePane)
|
||||
.Select(active => !SettingsPane.IsValueCreated || !object.ReferenceEquals(active, SettingsPane.Value)),
|
||||
execute: () => NavigateTo(SettingsPane.Value));
|
||||
execute: () => NavigateToGlobal.Send(NavigateToGlobal.ScreenType.Settings));
|
||||
}
|
||||
|
||||
private void HandleNavigateTo(NavigateToGlobal.ScreenType s)
|
||||
{
|
||||
ActivePane = s switch
|
||||
{
|
||||
NavigateToGlobal.ScreenType.ModeSelectionView => ModeSelectionVM,
|
||||
NavigateToGlobal.ScreenType.ModListGallery => Gallery,
|
||||
NavigateToGlobal.ScreenType.Installer => Installer.Value,
|
||||
NavigateToGlobal.ScreenType.Settings => SettingsPane.Value,
|
||||
_ => ActivePane
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsStartingFromModlist(out AbsolutePath modlistPath)
|
||||
@ -171,21 +188,23 @@ namespace Wabbajack
|
||||
if (path == default) return;
|
||||
var installer = Installer.Value;
|
||||
Settings.Installer.LastInstalledListLocation = path;
|
||||
NavigateTo(installer);
|
||||
NavigateToGlobal.Send(NavigateToGlobal.ScreenType.Installer);
|
||||
installer.ModListLocation.TargetPath = path;
|
||||
}
|
||||
|
||||
/*
|
||||
public void NavigateTo(ViewModel vm)
|
||||
{
|
||||
ActivePane = vm;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
public void NavigateTo<T>(T vm)
|
||||
where T : ViewModel, IBackNavigatingVM
|
||||
{
|
||||
vm.NavigateBackTarget = ActivePane;
|
||||
ActivePane = vm;
|
||||
}
|
||||
}*/
|
||||
|
||||
public async Task ShutdownApplication()
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ namespace Wabbajack.View_Models
|
||||
private static readonly Regex NameMatcher = new(@"(?<=\.)[^\.]+(?=\+State)", RegexOptions.Compiled);
|
||||
private readonly ILogger<ModListContentsVM> _logger;
|
||||
|
||||
public ModListContentsVM(ILogger<ModListContentsVM> logger, MainWindowVM mwvm) : base(logger, mwvm)
|
||||
public ModListContentsVM(ILogger<ModListContentsVM> logger, MainWindowVM mwvm) : base(logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_mwvm = mwvm;
|
||||
|
@ -8,6 +8,7 @@ using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.Paths.IO;
|
||||
|
||||
namespace Wabbajack
|
||||
@ -20,23 +21,23 @@ namespace Wabbajack
|
||||
public ICommand CompileCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> UpdateCommand { get; }
|
||||
|
||||
public ModeSelectionVM(MainWindowVM mainVM)
|
||||
public ModeSelectionVM()
|
||||
{
|
||||
_mainVM = mainVM;
|
||||
|
||||
InstallCommand = ReactiveCommand.Create(
|
||||
execute: () =>
|
||||
{
|
||||
/* TODO
|
||||
var path = mainVM.Settings.Installer.LastInstalledListLocation;
|
||||
if (path == default || !path.FileExists())
|
||||
{
|
||||
path = UIUtils.OpenFileDialog($"*{Ext.Wabbajack}|*{Ext.Wabbajack}");
|
||||
}
|
||||
_mainVM.OpenInstaller(path);
|
||||
*/
|
||||
});
|
||||
|
||||
CompileCommand = ReactiveCommand.Create(() => mainVM.NavigateTo(mainVM.Compiler.Value));
|
||||
BrowseCommand = ReactiveCommand.Create(() => mainVM.NavigateTo(mainVM.Gallery.Value));
|
||||
CompileCommand = ReactiveCommand.Create(() => NavigateToGlobal.Send(NavigateToGlobal.ScreenType.Compiler));
|
||||
BrowseCommand = ReactiveCommand.Create(() => NavigateToGlobal.Send(NavigateToGlobal.ScreenType.ModListGallery));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace Wabbajack.View_Models.Settings
|
||||
private readonly Client _wjClient;
|
||||
private IObservable<bool> IsUploading { get; }
|
||||
|
||||
public AuthorFilesVM(ILogger<AuthorFilesVM> logger, WabbajackApiTokenProvider token, Client wjClient, SettingsVM vm) : base(logger, vm.MWVM)
|
||||
public AuthorFilesVM(ILogger<AuthorFilesVM> logger, WabbajackApiTokenProvider token, Client wjClient, SettingsVM vm) : base(logger)
|
||||
{
|
||||
_token = token;
|
||||
_wjClient = wjClient;
|
||||
|
@ -20,7 +20,7 @@ namespace Wabbajack
|
||||
public List<LoginTargetVM> Downloaders { get; }
|
||||
|
||||
public LoginManagerVM(ILogger<LoginManagerVM> logger, SettingsVM settingsVM)
|
||||
: base(logger, settingsVM.MWVM)
|
||||
: base(logger)
|
||||
{
|
||||
/*
|
||||
Downloaders = DownloadDispatcher.Downloaders
|
||||
|
@ -28,7 +28,7 @@ namespace Wabbajack
|
||||
public ICommand OpenTerminalCommand { get; }
|
||||
|
||||
public SettingsVM(ILogger<SettingsVM> logger, MainWindowVM mainWindowVM, IServiceProvider provider)
|
||||
: base(logger, mainWindowVM)
|
||||
: base(logger)
|
||||
{
|
||||
MWVM = mainWindowVM;
|
||||
Login = new LoginManagerVM(provider.GetRequiredService<ILogger<LoginManagerVM>>(), this);
|
||||
|
@ -7,6 +7,7 @@ using ReactiveUI;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.Interventions;
|
||||
using Wabbajack.Messages;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
@ -28,11 +29,11 @@ namespace Wabbajack
|
||||
var cancel = new CancellationTokenSource();
|
||||
var oldPane = MainWindow.ActivePane;
|
||||
using var vm = await WebBrowserVM.GetNew(_logger);
|
||||
MainWindow.NavigateTo(vm);
|
||||
NavigateTo.Send(vm);
|
||||
vm.BackCommand = ReactiveCommand.Create(() =>
|
||||
{
|
||||
cancel.Cancel();
|
||||
MainWindow.NavigateTo(oldPane);
|
||||
NavigateTo.Send(oldPane);
|
||||
intervention.Cancel();
|
||||
});
|
||||
|
||||
@ -54,7 +55,7 @@ namespace Wabbajack
|
||||
wait.Dispose();
|
||||
}
|
||||
|
||||
MainWindow.NavigateTo(oldPane);
|
||||
NavigateTo.Send(oldPane);
|
||||
}
|
||||
|
||||
public async Task Handle(IStatusMessage msg)
|
||||
|
@ -19,19 +19,19 @@ namespace Wabbajack
|
||||
this.WhenAny(x => x.ViewModel.ModLists)
|
||||
.BindToStrict(this, x => x.ModListGalleryControl.ItemsSource)
|
||||
.DisposeWith(dispose);
|
||||
Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ViewModel.Error),
|
||||
this.WhenAny(x => x.ViewModel.Loaded),
|
||||
resultSelector: (err, loaded) =>
|
||||
{
|
||||
if (!err?.Succeeded ?? false) return true;
|
||||
return !loaded;
|
||||
})
|
||||
.DistinctUntilChanged()
|
||||
|
||||
this.WhenAny(x => x.ViewModel.LoadingLock.IsLoading)
|
||||
.Select(x => x ? Visibility.Visible : Visibility.Collapsed)
|
||||
.StartWith(Visibility.Collapsed)
|
||||
.BindToStrict(this, x => x.LoadingRing.Visibility)
|
||||
.BindTo(this, x => x.LoadingRing.Visibility)
|
||||
.DisposeWith(dispose);
|
||||
|
||||
this.WhenAny(x => x.ViewModel.LoadingLock.ErrorState)
|
||||
.Select(e => (e?.Succeeded ?? true) ? Visibility.Collapsed : Visibility.Visible)
|
||||
.StartWith(Visibility.Collapsed)
|
||||
.BindToStrict(this, x => x.ErrorIcon.Visibility)
|
||||
.DisposeWith(dispose);
|
||||
|
||||
Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ViewModel.ModLists.Count)
|
||||
.Select(x => x > 0),
|
||||
@ -45,11 +45,7 @@ namespace Wabbajack
|
||||
.StartWith(Visibility.Collapsed)
|
||||
.BindToStrict(this, x => x.NoneFound.Visibility)
|
||||
.DisposeWith(dispose);
|
||||
this.WhenAny(x => x.ViewModel.Error)
|
||||
.Select(e => (e?.Succeeded ?? true) ? Visibility.Collapsed : Visibility.Visible)
|
||||
.StartWith(Visibility.Collapsed)
|
||||
.BindToStrict(this, x => x.ErrorIcon.Visibility)
|
||||
.DisposeWith(dispose);
|
||||
|
||||
|
||||
this.BindStrict(ViewModel, vm => vm.Search, x => x.SearchBox.Text)
|
||||
.DisposeWith(dispose);
|
||||
|
@ -60,7 +60,7 @@
|
||||
<PackageReference Include="CefSharp.Wpf" Version="91.1.230">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="DynamicData" Version="7.2.1" />
|
||||
<PackageReference Include="DynamicData" Version="7.3.1" />
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.1.0">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
@ -78,9 +78,9 @@
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
|
||||
<PackageReference Include="PInvoke.User32" Version="0.7.104" />
|
||||
<PackageReference Include="ReactiveUI" Version="14.1.1" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="14.1.1" />
|
||||
<PackageReference Include="ReactiveUI.WPF" Version="14.1.1" />
|
||||
<PackageReference Include="ReactiveUI" Version="16.2.6" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="16.2.6" />
|
||||
<PackageReference Include="ReactiveUI.WPF" Version="16.2.6" />
|
||||
<PackageReference Include="Silk.NET.DXGI" Version="2.6.0" />
|
||||
<PackageReference Include="WPFThemes.DarkBlend" Version="1.0.8" />
|
||||
</ItemGroup>
|
||||
@ -104,4 +104,8 @@
|
||||
<SplashScreen Include="Resources\Wabba_Mouth_Small.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reactive;
|
||||
|
@ -4,8 +4,8 @@ namespace Wabbajack
|
||||
{
|
||||
public struct ErrorResponse : IErrorResponse
|
||||
{
|
||||
public readonly static ErrorResponse Success = Succeed();
|
||||
public readonly static ErrorResponse Failure = new ErrorResponse();
|
||||
public static readonly ErrorResponse Success = Succeed();
|
||||
public static readonly ErrorResponse Failure = new ErrorResponse();
|
||||
|
||||
public bool Succeeded { get; }
|
||||
public Exception? Exception { get; }
|
74
Wabbajack.Lib/LoadingLock.cs
Normal file
74
Wabbajack.Lib/LoadingLock.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Reactive.Disposables;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
|
||||
namespace Wabbajack.Models;
|
||||
|
||||
public class LoadingLock : ReactiveObject, IDisposable
|
||||
{
|
||||
private readonly CompositeDisposable _disposable;
|
||||
|
||||
public ErrorResponse? ErrorState { get; set; }
|
||||
|
||||
public LoadingLock()
|
||||
{
|
||||
_disposable = new CompositeDisposable();
|
||||
|
||||
this.WhenAnyValue(vm => vm.LoadLevel)
|
||||
.Subscribe(v => IsLoading = v > 0)
|
||||
.DisposeWith(_disposable);
|
||||
}
|
||||
|
||||
[Reactive] public int LoadLevel { get; private set; }
|
||||
|
||||
[Reactive] public bool IsLoading { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_disposable.Dispose();
|
||||
}
|
||||
|
||||
public LockContext WithLoading()
|
||||
{
|
||||
RxApp.MainThreadScheduler.Schedule(0, (_, _) => { LoadLevel++;
|
||||
return Disposable.Empty;
|
||||
});
|
||||
return new LockContext(this);
|
||||
}
|
||||
|
||||
public class LockContext : IDisposable
|
||||
{
|
||||
private readonly LoadingLock _parent;
|
||||
private bool _disposed;
|
||||
|
||||
public LockContext(LoadingLock parent)
|
||||
{
|
||||
_parent = parent;
|
||||
_disposed = false;
|
||||
}
|
||||
|
||||
public void Succeed()
|
||||
{
|
||||
_parent.ErrorState = ErrorResponse.Success;
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Fail()
|
||||
{
|
||||
_parent.ErrorState = ErrorResponse.Failure;
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
RxApp.MainThreadScheduler.Schedule(0, (_, _) => { _parent.LoadLevel--;
|
||||
return Disposable.Empty;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -4,15 +4,18 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Wabbajack.Models;
|
||||
|
||||
namespace Wabbajack.Lib
|
||||
{
|
||||
public class ViewModel : ReactiveObject, IDisposable
|
||||
public class ViewModel : ReactiveObject, IDisposable, IActivatableViewModel
|
||||
{
|
||||
private readonly Lazy<CompositeDisposable> _compositeDisposable = new Lazy<CompositeDisposable>();
|
||||
private readonly Lazy<CompositeDisposable> _compositeDisposable = new();
|
||||
[JsonIgnore]
|
||||
public CompositeDisposable CompositeDisposable => _compositeDisposable.Value;
|
||||
|
||||
[JsonIgnore] public LoadingLock LoadingLock { get; } = new();
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (_compositeDisposable.IsValueCreated)
|
||||
@ -30,5 +33,7 @@ namespace Wabbajack.Lib
|
||||
item = newItem;
|
||||
this.RaisePropertyChanged(propertyName);
|
||||
}
|
||||
|
||||
public ViewModelActivator Activator { get; } = new();
|
||||
}
|
||||
}
|
||||
|
@ -35,10 +35,10 @@
|
||||
<Version>0.50.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ReactiveUI">
|
||||
<Version>14.1.1</Version>
|
||||
<Version>16.2.6</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ReactiveUI.Fody">
|
||||
<Version>14.1.1</Version>
|
||||
<Version>16.2.6</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SharpCompress">
|
||||
<Version>0.28.3</Version>
|
||||
|
Loading…
Reference in New Issue
Block a user