mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
commit
3180678a87
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
@ -17,6 +18,7 @@ using Wabbajack.App.ViewModels;
|
|||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Downloaders;
|
using Wabbajack.Downloaders;
|
||||||
using Wabbajack.DTOs;
|
using Wabbajack.DTOs;
|
||||||
|
using Wabbajack.DTOs.JsonConverters;
|
||||||
using Wabbajack.Installer;
|
using Wabbajack.Installer;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
@ -43,6 +45,7 @@ namespace Wabbajack.App.Controls
|
|||||||
private readonly DownloadDispatcher _dispatcher;
|
private readonly DownloadDispatcher _dispatcher;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IResource<DownloadDispatcher> _downloadLimiter;
|
private readonly IResource<DownloadDispatcher> _downloadLimiter;
|
||||||
|
private readonly DTOSerializer _dtos;
|
||||||
|
|
||||||
public string Title => _metadata.ImageContainsTitle ? "" : _metadata.Title;
|
public string Title => _metadata.ImageContainsTitle ? "" : _metadata.Title;
|
||||||
public string MachineURL => _metadata.Links.MachineURL;
|
public string MachineURL => _metadata.Links.MachineURL;
|
||||||
@ -74,7 +77,7 @@ namespace Wabbajack.App.Controls
|
|||||||
|
|
||||||
public BrowseItemViewModel(ModlistMetadata metadata, ModListSummary summary, HttpClient client, IResource<HttpClient> limiter,
|
public BrowseItemViewModel(ModlistMetadata metadata, ModListSummary summary, HttpClient client, IResource<HttpClient> limiter,
|
||||||
FileHashCache hashCache, Configuration configuration, DownloadDispatcher dispatcher, IResource<DownloadDispatcher> downloadLimiter, GameLocator gameLocator,
|
FileHashCache hashCache, Configuration configuration, DownloadDispatcher dispatcher, IResource<DownloadDispatcher> downloadLimiter, GameLocator gameLocator,
|
||||||
ILogger logger)
|
DTOSerializer dtos, ILogger logger)
|
||||||
{
|
{
|
||||||
Activator = new ViewModelActivator();
|
Activator = new ViewModelActivator();
|
||||||
_metadata = metadata;
|
_metadata = metadata;
|
||||||
@ -86,6 +89,8 @@ namespace Wabbajack.App.Controls
|
|||||||
_dispatcher = dispatcher;
|
_dispatcher = dispatcher;
|
||||||
_downloadLimiter = downloadLimiter;
|
_downloadLimiter = downloadLimiter;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_dtos = dtos;
|
||||||
|
|
||||||
var haveGame = gameLocator.IsInstalled(_metadata.Game);
|
var haveGame = gameLocator.IsInstalled(_metadata.Game);
|
||||||
Tags = metadata.tags
|
Tags = metadata.tags
|
||||||
.Select(t => new TagViewModel(t, "ModList"))
|
.Select(t => new TagViewModel(t, "ModList"))
|
||||||
@ -150,6 +155,9 @@ namespace Wabbajack.App.Controls
|
|||||||
|
|
||||||
_hashCache.FileHashWriteCache(ModListLocation, hash);
|
_hashCache.FileHashWriteCache(ModListLocation, hash);
|
||||||
|
|
||||||
|
var metadataPath = ModListLocation.WithExtension(Ext.MetaData);
|
||||||
|
await metadataPath.WriteAllTextAsync(_dtos.Serialize(_metadata));
|
||||||
|
|
||||||
await UpdateState();
|
await UpdateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
Wabbajack.App/Messages/ConfigureLauncher.cs
Normal file
9
Wabbajack.App/Messages/ConfigureLauncher.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Wabbajack.Paths;
|
||||||
|
|
||||||
|
namespace Wabbajack.App.Messages
|
||||||
|
{
|
||||||
|
public record ConfigureLauncher(AbsolutePath InstallFolder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ using Wabbajack.Paths;
|
|||||||
|
|
||||||
namespace Wabbajack.App.Messages
|
namespace Wabbajack.App.Messages
|
||||||
{
|
{
|
||||||
public record StartInstallation(AbsolutePath ModListPath, AbsolutePath Install, AbsolutePath Download)
|
public record StartInstallation(AbsolutePath ModListPath, AbsolutePath Install, AbsolutePath Download, ModlistMetadata? Metadata)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -73,5 +73,10 @@ namespace Wabbajack.App.Models
|
|||||||
{
|
{
|
||||||
return (await GetAll()).Settings.FirstOrDefault(f => f.ModList == modListPath);
|
return (await GetAll()).Settings.FirstOrDefault(f => f.ModList == modListPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<InstallationConfigurationSetting?> GetByInstallFolder(AbsolutePath folder)
|
||||||
|
{
|
||||||
|
return (await GetAll()).Settings.FirstOrDefault(f => f.Install == folder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,6 +24,7 @@ using Wabbajack.Networking.WabbajackClientApi;
|
|||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Wabbajack.Downloaders;
|
using Wabbajack.Downloaders;
|
||||||
|
using Wabbajack.DTOs.JsonConverters;
|
||||||
using Wabbajack.Installer;
|
using Wabbajack.Installer;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
@ -52,6 +53,7 @@ namespace Wabbajack.App.Screens
|
|||||||
private SourceCache<GameSelectorItemViewModel, string> _gamesList = new(x => x.Name);
|
private SourceCache<GameSelectorItemViewModel, string> _gamesList = new(x => x.Name);
|
||||||
public readonly ReadOnlyObservableCollection<GameSelectorItemViewModel> _filteredGamesList;
|
public readonly ReadOnlyObservableCollection<GameSelectorItemViewModel> _filteredGamesList;
|
||||||
private readonly GameLocator _gameLocator;
|
private readonly GameLocator _gameLocator;
|
||||||
|
private readonly DTOSerializer _dtos;
|
||||||
public ReadOnlyObservableCollection<GameSelectorItemViewModel> GamesList => _filteredGamesList;
|
public ReadOnlyObservableCollection<GameSelectorItemViewModel> GamesList => _filteredGamesList;
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
@ -67,7 +69,7 @@ namespace Wabbajack.App.Screens
|
|||||||
[Reactive] public bool ShowNSFW { get; set; } = false;
|
[Reactive] public bool ShowNSFW { get; set; } = false;
|
||||||
|
|
||||||
public BrowseViewModel(ILogger<BrowseViewModel> logger, Client wjClient, HttpClient httpClient, IResource<HttpClient> limiter, FileHashCache hashCache,
|
public BrowseViewModel(ILogger<BrowseViewModel> logger, Client wjClient, HttpClient httpClient, IResource<HttpClient> limiter, FileHashCache hashCache,
|
||||||
IResource<DownloadDispatcher> dispatcherLimiter, DownloadDispatcher dispatcher, GameLocator gameLocator, Configuration configuration)
|
IResource<DownloadDispatcher> dispatcherLimiter, DownloadDispatcher dispatcher, GameLocator gameLocator, DTOSerializer dtos, Configuration configuration)
|
||||||
{
|
{
|
||||||
Activator = new ViewModelActivator();
|
Activator = new ViewModelActivator();
|
||||||
_wjClient = wjClient;
|
_wjClient = wjClient;
|
||||||
@ -79,6 +81,7 @@ namespace Wabbajack.App.Screens
|
|||||||
_dispatcher = dispatcher;
|
_dispatcher = dispatcher;
|
||||||
_dispatcherLimiter = dispatcherLimiter;
|
_dispatcherLimiter = dispatcherLimiter;
|
||||||
_gameLocator = gameLocator;
|
_gameLocator = gameLocator;
|
||||||
|
_dtos = dtos;
|
||||||
|
|
||||||
|
|
||||||
IObservable<Func<BrowseItemViewModel, bool>> searchTextPredicates = this.ObservableForProperty(vm => vm.SearchText)
|
IObservable<Func<BrowseItemViewModel, bool>> searchTextPredicates = this.ObservableForProperty(vm => vm.SearchText)
|
||||||
@ -198,7 +201,7 @@ namespace Wabbajack.App.Screens
|
|||||||
summary = new ModListSummary();
|
summary = new ModListSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BrowseItemViewModel(m, summary, _httpClient, _limiter, _hashCache, _configuration, _dispatcher, _dispatcherLimiter, _gameLocator, _logger);
|
return new BrowseItemViewModel(m, summary, _httpClient, _limiter, _hashCache, _configuration, _dispatcher, _dispatcherLimiter, _gameLocator, _dtos, _logger);
|
||||||
});
|
});
|
||||||
|
|
||||||
_modLists.Edit(lsts =>
|
_modLists.Edit(lsts =>
|
||||||
|
37
Wabbajack.App/Screens/LauncherView.axaml
Normal file
37
Wabbajack.App/Screens/LauncherView.axaml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="clr-namespace:Wabbajack.App.Controls"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Wabbajack.App.Screens.LauncherView">
|
||||||
|
<Grid RowDefinitions="*, Auto">
|
||||||
|
<Viewbox Grid.Row="0"
|
||||||
|
Name="Banner"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Stretch="UniformToFill">
|
||||||
|
<Image x:Name="ModListImage" Margin="0,0,0,0" Source="../Assets/Wabba_Mouth.png" />
|
||||||
|
</Viewbox>
|
||||||
|
<Grid Grid.Row="0" RowDefinitions="40, 40" HorizontalAlignment="Left" VerticalAlignment="Bottom">
|
||||||
|
<TextBlock x:Name="ModListName"></TextBlock>
|
||||||
|
</Grid>
|
||||||
|
<Grid Margin="40" RowDefinitions="40, 40, 40, *" ColumnDefinitions="100, *, 200" Grid.Row="1">
|
||||||
|
<Label Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center">ModList:</Label>
|
||||||
|
<TextBox Grid.Column="1" Grid.Row="0" IsEnabled="False" Height="20" x:Name="ModList"></TextBox>
|
||||||
|
|
||||||
|
<Label Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center">Location:</Label>
|
||||||
|
<TextBox Grid.Column="1" Grid.Row="1" IsEnabled="False" Height="20" x:Name="InstallPath"></TextBox>
|
||||||
|
|
||||||
|
<Grid Grid.Column="1" Grid.Row="3" Grid.ColumnDefinitions="*, *, *" HorizontalAlignment="Center">
|
||||||
|
<Button Grid.Column="0" x:Name="WebsiteButton">Website</Button>
|
||||||
|
<Button Grid.Column="1" x:Name="ReadmeButton">Readme</Button>
|
||||||
|
<Button Grid.Column="2" x:Name="LocalFilesButton">Local Files</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<controls:LargeIconButton x:Name="PlayGame" Margin="40, 0, 0, 0" Grid.Row="0" Grid.Column="2" Grid.RowSpan="4" Icon="PlayCircle" Text="Play">
|
||||||
|
|
||||||
|
</controls:LargeIconButton>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
33
Wabbajack.App/Screens/LauncherView.axaml.cs
Normal file
33
Wabbajack.App/Screens/LauncherView.axaml.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System.Reactive.Disposables;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using ReactiveUI;
|
||||||
|
using Wabbajack.App.Views;
|
||||||
|
|
||||||
|
namespace Wabbajack.App.Screens
|
||||||
|
{
|
||||||
|
public partial class LauncherView : ScreenBase<LauncherViewModel>
|
||||||
|
{
|
||||||
|
public LauncherView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.WhenActivated(disposables =>
|
||||||
|
{
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.Image, view => view.ModListImage.Source)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.Title, view => view.ModList.Text)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.InstallFolder, view => view.InstallPath.Text,
|
||||||
|
v => v.ToString())
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.PlayButton, view => view.PlayGame.Button)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
102
Wabbajack.App/Screens/LauncherViewModel.cs
Normal file
102
Wabbajack.App/Screens/LauncherViewModel.cs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using GameFinder.StoreHandlers.Origin.DTO;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using Wabbajack.App.Extensions;
|
||||||
|
using Wabbajack.App.Messages;
|
||||||
|
using Wabbajack.App.Models;
|
||||||
|
using Wabbajack.App.ViewModels;
|
||||||
|
using Wabbajack.Common;
|
||||||
|
using Wabbajack.DTOs;
|
||||||
|
using Wabbajack.DTOs.SavedSettings;
|
||||||
|
using Wabbajack.Paths;
|
||||||
|
using Wabbajack.Paths.IO;
|
||||||
|
|
||||||
|
namespace Wabbajack.App.Screens
|
||||||
|
{
|
||||||
|
public class LauncherViewModel : ViewModelBase, IActivatableViewModel, IReceiver<ConfigureLauncher>
|
||||||
|
{
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public AbsolutePath InstallFolder { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public IBitmap Image { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public InstallationConfigurationSetting? Setting { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string Title { get; set; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> PlayButton;
|
||||||
|
private readonly ILogger<LauncherViewModel> _logger;
|
||||||
|
|
||||||
|
public LauncherViewModel(ILogger<LauncherViewModel> logger, InstallationStateManager manager)
|
||||||
|
{
|
||||||
|
Activator = new ViewModelActivator();
|
||||||
|
PlayButton = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
StartGame().FireAndForget();
|
||||||
|
});
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
|
this.WhenActivated(disposables =>
|
||||||
|
{
|
||||||
|
this.WhenAnyValue(v => v.InstallFolder)
|
||||||
|
.SelectAsync(disposables, async folder => await manager.GetByInstallFolder(folder))
|
||||||
|
.ObserveOn(RxApp.MainThreadScheduler)
|
||||||
|
.Where(v => v != null)
|
||||||
|
.BindTo(this, vm => vm.Setting)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.WhenAnyValue(v => v.Setting)
|
||||||
|
.Where(v => v != default)
|
||||||
|
.Select(v => new Bitmap((v!.Image).ToString()))
|
||||||
|
.BindTo(this, vm => vm.Image)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.WhenAnyValue(v => v.Setting)
|
||||||
|
.Where(v => v is { Metadata: { } })
|
||||||
|
.Select(v => $"{v!.Metadata!.Title} v{v!.Metadata.Version}")
|
||||||
|
.BindTo(this, vm => vm.Title)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task StartGame()
|
||||||
|
{
|
||||||
|
var mo2Path = InstallFolder.Combine("ModOrganizer.exe");
|
||||||
|
var gamePath = GameRegistry.Games.Values.Select(g => g.MainExecutable)
|
||||||
|
.Where(ge => ge != null)
|
||||||
|
.Select(ge => InstallFolder.Combine(ge!))
|
||||||
|
.FirstOrDefault(ge => ge.FileExists());
|
||||||
|
if (mo2Path.FileExists())
|
||||||
|
{
|
||||||
|
Process.Start(mo2Path.ToString());
|
||||||
|
}
|
||||||
|
else if (gamePath.FileExists())
|
||||||
|
{
|
||||||
|
Process.Start(gamePath.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogError("No way to launch game, no acceptable executable found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Receive(ConfigureLauncher val)
|
||||||
|
{
|
||||||
|
InstallFolder = val.InstallFolder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@
|
|||||||
<Viewbox Grid.Row="3" HorizontalAlignment="Center"
|
<Viewbox Grid.Row="3" HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Stretch="Uniform">
|
Stretch="Uniform">
|
||||||
<Image x:Name="SlideImage" Source="C:\tmp\modlist-image.png"></Image>
|
<Image x:Name="SlideImage"></Image>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Grid Grid.Row="4" HorizontalAlignment="Center" ColumnDefinitions="40, 40, 40, 40">
|
<Grid Grid.Row="4" HorizontalAlignment="Center" ColumnDefinitions="40, 40, 40, 40">
|
||||||
<Button Grid.Column="0" x:Name="PrevSlide"><i:MaterialIcon Kind="ArrowLeft"></i:MaterialIcon></Button>
|
<Button Grid.Column="0" x:Name="PrevSlide"><i:MaterialIcon Kind="ArrowLeft"></i:MaterialIcon></Button>
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
@ -13,12 +14,17 @@ using Microsoft.Extensions.Logging;
|
|||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
using Wabbajack.App.Messages;
|
using Wabbajack.App.Messages;
|
||||||
|
using Wabbajack.App.Models;
|
||||||
|
using Wabbajack.App.Screens;
|
||||||
|
using Wabbajack.App.Utilities;
|
||||||
using Wabbajack.App.ViewModels.SubViewModels;
|
using Wabbajack.App.ViewModels.SubViewModels;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.DTOs;
|
using Wabbajack.DTOs;
|
||||||
using Wabbajack.DTOs.DownloadStates;
|
using Wabbajack.DTOs.DownloadStates;
|
||||||
using Wabbajack.DTOs.JsonConverters;
|
using Wabbajack.DTOs.JsonConverters;
|
||||||
|
using Wabbajack.DTOs.SavedSettings;
|
||||||
using Wabbajack.Installer;
|
using Wabbajack.Installer;
|
||||||
|
using Wabbajack.Paths.IO;
|
||||||
using Wabbajack.RateLimiter;
|
using Wabbajack.RateLimiter;
|
||||||
|
|
||||||
namespace Wabbajack.App.ViewModels
|
namespace Wabbajack.App.ViewModels
|
||||||
@ -36,6 +42,7 @@ namespace Wabbajack.App.ViewModels
|
|||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
private Timer _slideTimer;
|
private Timer _slideTimer;
|
||||||
private int _currentSlideIndex;
|
private int _currentSlideIndex;
|
||||||
|
private readonly InstallationStateManager _installStateManager;
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public SlideViewModel Slide { get; set; }
|
public SlideViewModel Slide { get; set; }
|
||||||
@ -58,13 +65,15 @@ namespace Wabbajack.App.ViewModels
|
|||||||
[Reactive] public Percent StepsProgress { get; set; } = Percent.Zero;
|
[Reactive] public Percent StepsProgress { get; set; } = Percent.Zero;
|
||||||
[Reactive] public Percent StepProgress { get; set; } = Percent.Zero;
|
[Reactive] public Percent StepProgress { get; set; } = Percent.Zero;
|
||||||
|
|
||||||
public StandardInstallationViewModel(ILogger<StandardInstallationViewModel> logger, IServiceProvider provider, GameLocator locator, DTOSerializer dtos, HttpClient httpClient)
|
public StandardInstallationViewModel(ILogger<StandardInstallationViewModel> logger, IServiceProvider provider, GameLocator locator, DTOSerializer dtos,
|
||||||
|
HttpClient httpClient, InstallationStateManager manager)
|
||||||
{
|
{
|
||||||
_provider = provider;
|
_provider = provider;
|
||||||
_locator = locator;
|
_locator = locator;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_dtos = dtos;
|
_dtos = dtos;
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
|
_installStateManager = manager;
|
||||||
Activator = new ViewModelActivator();
|
Activator = new ViewModelActivator();
|
||||||
|
|
||||||
this.WhenActivated(disposables => {
|
this.WhenActivated(disposables => {
|
||||||
@ -142,6 +151,7 @@ namespace Wabbajack.App.ViewModels
|
|||||||
_config.Downloads = msg.Download;
|
_config.Downloads = msg.Download;
|
||||||
_config.Install = msg.Install;
|
_config.Install = msg.Install;
|
||||||
_config.ModlistArchive = msg.ModListPath;
|
_config.ModlistArchive = msg.ModListPath;
|
||||||
|
_config.Metadata = msg.Metadata;
|
||||||
|
|
||||||
_logger.LogInformation("Loading ModList Data");
|
_logger.LogInformation("Loading ModList Data");
|
||||||
_config.ModList = await StandardInstaller.LoadFromFile(_dtos, msg.ModListPath);
|
_config.ModList = await StandardInstaller.LoadFromFile(_dtos, msg.ModListPath);
|
||||||
@ -180,7 +190,34 @@ namespace Wabbajack.App.ViewModels
|
|||||||
};
|
};
|
||||||
|
|
||||||
_logger.LogInformation("Installer created, starting the installation process");
|
_logger.LogInformation("Installer created, starting the installation process");
|
||||||
await _installer.Begin(CancellationToken.None);
|
var result = await _installer.Begin(CancellationToken.None);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
await SaveConfigAndContinue(_config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveConfigAndContinue(InstallerConfiguration config)
|
||||||
|
{
|
||||||
|
var path = config.Install.Combine("modlist-image.png");
|
||||||
|
{
|
||||||
|
var image = await ModListUtilities.GetModListImageStream(config.ModlistArchive);
|
||||||
|
await using var os = path.Open(FileMode.Create, FileAccess.Write);
|
||||||
|
await image.CopyToAsync(os);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _installStateManager.SetLastState(new InstallationConfigurationSetting
|
||||||
|
{
|
||||||
|
Downloads = config.Downloads,
|
||||||
|
Install = config.Install,
|
||||||
|
Metadata = config.Metadata,
|
||||||
|
ModList = config.ModlistArchive,
|
||||||
|
Image = path
|
||||||
|
});
|
||||||
|
|
||||||
|
MessageBus.Instance.Send(new ConfigureLauncher(config.Install));
|
||||||
|
MessageBus.Instance.Send(new NavigateTo(typeof(LauncherViewModel)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -46,6 +46,8 @@ namespace Wabbajack.App
|
|||||||
services.AddSingleton<IScreenView, StandardInstallationView>();
|
services.AddSingleton<IScreenView, StandardInstallationView>();
|
||||||
services.AddSingleton<IScreenView, SettingsView>();
|
services.AddSingleton<IScreenView, SettingsView>();
|
||||||
services.AddSingleton<IScreenView, BrowseView>();
|
services.AddSingleton<IScreenView, BrowseView>();
|
||||||
|
services.AddSingleton<IScreenView, LauncherView>();
|
||||||
|
|
||||||
services.AddSingleton<InstallationStateManager>();
|
services.AddSingleton<InstallationStateManager>();
|
||||||
services.AddSingleton<HttpClient>();
|
services.AddSingleton<HttpClient>();
|
||||||
|
|
||||||
@ -56,6 +58,7 @@ namespace Wabbajack.App
|
|||||||
services.AddAllSingleton<IReceiverMarker, NexusLoginViewModel>();
|
services.AddAllSingleton<IReceiverMarker, NexusLoginViewModel>();
|
||||||
services.AddAllSingleton<IReceiverMarker, LoversLabOAuthLoginViewModel>();
|
services.AddAllSingleton<IReceiverMarker, LoversLabOAuthLoginViewModel>();
|
||||||
services.AddAllSingleton<IReceiverMarker, VectorPlexusOAuthLoginViewModel>();
|
services.AddAllSingleton<IReceiverMarker, VectorPlexusOAuthLoginViewModel>();
|
||||||
|
services.AddAllSingleton<IReceiverMarker, LauncherViewModel>();
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
services.AddAllSingleton<IDownloader, IDownloader<Manual>, ManualDownloader>();
|
services.AddAllSingleton<IDownloader, IDownloader<Manual>, ManualDownloader>();
|
||||||
|
21
Wabbajack.App/Utilities/ModListUtilities.cs
Normal file
21
Wabbajack.App/Utilities/ModListUtilities.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Wabbajack.Common;
|
||||||
|
using Wabbajack.Paths;
|
||||||
|
using Wabbajack.Paths.IO;
|
||||||
|
|
||||||
|
namespace Wabbajack.App.Utilities
|
||||||
|
{
|
||||||
|
public class ModListUtilities
|
||||||
|
{
|
||||||
|
public static async Task<MemoryStream> GetModListImageStream(AbsolutePath modList)
|
||||||
|
{
|
||||||
|
await using var fs = modList.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
|
using var ar = new ZipArchive(fs, ZipArchiveMode.Read);
|
||||||
|
var entry = ar.GetEntry("modlist-image.png");
|
||||||
|
await using var stream = entry!.Open();
|
||||||
|
return new MemoryStream(await stream.ReadAllAsync());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ using ReactiveUI.Validation.Extensions;
|
|||||||
using Wabbajack.App.Extensions;
|
using Wabbajack.App.Extensions;
|
||||||
using Wabbajack.App.Messages;
|
using Wabbajack.App.Messages;
|
||||||
using Wabbajack.App.Models;
|
using Wabbajack.App.Models;
|
||||||
|
using Wabbajack.App.Utilities;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.DTOs;
|
using Wabbajack.DTOs;
|
||||||
using Wabbajack.DTOs.JsonConverters;
|
using Wabbajack.DTOs.JsonConverters;
|
||||||
@ -63,7 +64,7 @@ namespace Wabbajack.App.ViewModels
|
|||||||
this.ValidationRule(x => x.Install, p => p.DirectoryExists(), "Install folder file must exist");
|
this.ValidationRule(x => x.Install, p => p.DirectoryExists(), "Install folder file must exist");
|
||||||
this.ValidationRule(x => x.Download, p => p != default, "Download folder must be set");
|
this.ValidationRule(x => x.Download, p => p != default, "Download folder must be set");
|
||||||
|
|
||||||
BeginCommand = ReactiveCommand.Create(StartInstall, this.IsValid());
|
BeginCommand = ReactiveCommand.Create(() => {StartInstall().FireAndForget();}, this.IsValid());
|
||||||
|
|
||||||
|
|
||||||
this.WhenAnyValue(t => t.ModListPath)
|
this.WhenAnyValue(t => t.ModListPath)
|
||||||
@ -97,26 +98,30 @@ namespace Wabbajack.App.ViewModels
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartInstall()
|
private async Task StartInstall()
|
||||||
{
|
{
|
||||||
|
ModlistMetadata? metadata = null;
|
||||||
|
var metadataPath = ModListPath.WithExtension(Ext.MetaData);
|
||||||
|
if (metadataPath.FileExists())
|
||||||
|
{
|
||||||
|
metadata = _dtos.Deserialize<ModlistMetadata>(await metadataPath.ReadAllTextAsync());
|
||||||
|
}
|
||||||
|
|
||||||
_stateManager.SetLastState(new InstallationConfigurationSetting
|
_stateManager.SetLastState(new InstallationConfigurationSetting
|
||||||
{
|
{
|
||||||
ModList = ModListPath,
|
ModList = ModListPath,
|
||||||
Downloads = Download,
|
Downloads = Download,
|
||||||
Install = Install
|
Install = Install,
|
||||||
|
Metadata = metadata
|
||||||
}).FireAndForget();
|
}).FireAndForget();
|
||||||
|
|
||||||
MessageBus.Instance.Send(new NavigateTo(typeof(StandardInstallationViewModel)));
|
MessageBus.Instance.Send(new NavigateTo(typeof(StandardInstallationViewModel)));
|
||||||
MessageBus.Instance.Send(new StartInstallation(ModListPath, Install, Download));
|
MessageBus.Instance.Send(new StartInstallation(ModListPath, Install, Download, metadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IBitmap> LoadModListImage(AbsolutePath path)
|
private async Task<IBitmap> LoadModListImage(AbsolutePath path)
|
||||||
{
|
{
|
||||||
await using var fs = path.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
return new Bitmap(await ModListUtilities.GetModListImageStream(path));
|
||||||
using var ar = new ZipArchive(fs, ZipArchiveMode.Read);
|
|
||||||
var entry = ar.GetEntry("modlist-image.png");
|
|
||||||
await using var stream = entry!.Open();
|
|
||||||
return new Bitmap(new MemoryStream(await stream.ReadAllAsync()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ModList> LoadModList(AbsolutePath modlist)
|
private async Task<ModList> LoadModList(AbsolutePath modlist)
|
||||||
|
@ -14,9 +14,11 @@ using ReactiveUI.Fody.Helpers;
|
|||||||
using ReactiveUI.Validation.Helpers;
|
using ReactiveUI.Validation.Helpers;
|
||||||
using Wabbajack.App.Interfaces;
|
using Wabbajack.App.Interfaces;
|
||||||
using Wabbajack.App.Messages;
|
using Wabbajack.App.Messages;
|
||||||
|
using Wabbajack.App.Models;
|
||||||
using Wabbajack.App.Screens;
|
using Wabbajack.App.Screens;
|
||||||
using Wabbajack.App.Views;
|
using Wabbajack.App.Views;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
|
using Wabbajack.Paths.IO;
|
||||||
using Wabbajack.RateLimiter;
|
using Wabbajack.RateLimiter;
|
||||||
|
|
||||||
namespace Wabbajack.App.ViewModels
|
namespace Wabbajack.App.ViewModels
|
||||||
@ -28,6 +30,7 @@ namespace Wabbajack.App.ViewModels
|
|||||||
private readonly IResource[] _resources;
|
private readonly IResource[] _resources;
|
||||||
private StatusReport[] _prevReport;
|
private StatusReport[] _prevReport;
|
||||||
private readonly Task _resourcePoller;
|
private readonly Task _resourcePoller;
|
||||||
|
private readonly InstallationStateManager _manager;
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public Control CurrentScreen { get; set; }
|
public Control CurrentScreen { get; set; }
|
||||||
@ -44,11 +47,13 @@ namespace Wabbajack.App.ViewModels
|
|||||||
[Reactive]
|
[Reactive]
|
||||||
public string ResourceStatus { get; set; }
|
public string ResourceStatus { get; set; }
|
||||||
|
|
||||||
public MainWindowViewModel(IEnumerable<IScreenView> screens, IEnumerable<IResource> resources, IServiceProvider provider)
|
public MainWindowViewModel(IEnumerable<IScreenView> screens, IEnumerable<IResource> resources, IServiceProvider provider,
|
||||||
|
InstallationStateManager manager)
|
||||||
{
|
{
|
||||||
_provider = provider;
|
_provider = provider;
|
||||||
_screens = screens;
|
_screens = screens;
|
||||||
_resources = resources.ToArray();
|
_resources = resources.ToArray();
|
||||||
|
_manager = manager;
|
||||||
|
|
||||||
_prevReport = NextReport();
|
_prevReport = NextReport();
|
||||||
|
|
||||||
@ -74,10 +79,27 @@ namespace Wabbajack.App.ViewModels
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Receive(new NavigateTo(typeof(ModeSelectionViewModel)));
|
LoadFirstScreen().FireAndForget();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task LoadFirstScreen()
|
||||||
|
{
|
||||||
|
var setting = await _manager.GetLastState();
|
||||||
|
if (setting.Install != default && setting.Install.DirectoryExists())
|
||||||
|
{
|
||||||
|
BreadCrumbs =
|
||||||
|
BreadCrumbs.Push((Control)_screens.First(s => s.ViewModelType == typeof(ModeSelectionViewModel)));
|
||||||
|
|
||||||
|
MessageBus.Instance.Send(new ConfigureLauncher(setting.Install));
|
||||||
|
Receive(new NavigateTo(typeof(LauncherViewModel)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Receive(new NavigateTo(typeof(ModeSelectionViewModel)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private StatusReport[] NextReport()
|
private StatusReport[] NextReport()
|
||||||
{
|
{
|
||||||
return _resources.Select(r => r.StatusReport).ToArray();
|
return _resources.Select(r => r.StatusReport).ToArray();
|
||||||
|
@ -41,6 +41,10 @@
|
|||||||
<DependentUpon>SettingsView.axaml</DependentUpon>
|
<DependentUpon>SettingsView.axaml</DependentUpon>
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="Screens\StandardInstallationView.axaml.cs">
|
||||||
|
<DependentUpon>StandardInstallationView.axaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="AferBuild" AfterTargets="Build">
|
<Target Name="AferBuild" AfterTargets="Build">
|
||||||
|
@ -19,5 +19,6 @@ namespace Wabbajack.Common
|
|||||||
public static Extension Dds = new(".dds");
|
public static Extension Dds = new(".dds");
|
||||||
public static Extension Json = new(".json");
|
public static Extension Json = new(".json");
|
||||||
public static Extension Md = new(".md");
|
public static Extension Md = new(".md");
|
||||||
|
public static Extension MetaData = new(".metadata");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,5 +16,9 @@ namespace Wabbajack.DTOs.SavedSettings
|
|||||||
public AbsolutePath ModList { get; set; }
|
public AbsolutePath ModList { get; set; }
|
||||||
public AbsolutePath Install { get; set; }
|
public AbsolutePath Install { get; set; }
|
||||||
public AbsolutePath Downloads { get; set; }
|
public AbsolutePath Downloads { get; set; }
|
||||||
|
|
||||||
|
public ModlistMetadata? Metadata { get; set; }
|
||||||
|
|
||||||
|
public AbsolutePath Image { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,5 +12,7 @@ namespace Wabbajack.Installer
|
|||||||
public SystemParameters? SystemParameters { get; set; }
|
public SystemParameters? SystemParameters { get; set; }
|
||||||
public Game Game { get; set; }
|
public Game Game { get; set; }
|
||||||
public AbsolutePath GameFolder { get; set; }
|
public AbsolutePath GameFolder { get; set; }
|
||||||
|
|
||||||
|
public ModlistMetadata? Metadata { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user