mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Fixed nexus logins
This commit is contained in:
parent
cb7baa5382
commit
2ea4eda9b4
@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
@ -9,6 +12,7 @@ using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.Networking.Http.Interfaces;
|
||||
using Wabbajack.UserIntervention;
|
||||
|
||||
namespace Wabbajack.LoginManagers;
|
||||
|
||||
@ -17,6 +21,7 @@ public class NexusLoginManager : ViewModel, INeedsLogin
|
||||
private readonly ILogger<NexusLoginManager> _logger;
|
||||
private readonly ITokenProvider<NexusApiState> _token;
|
||||
private readonly IUserInterventionHandler _handler;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public string SiteName { get; } = "Nexus Mods";
|
||||
public ICommand TriggerLogin { get; set; }
|
||||
@ -27,10 +32,11 @@ public class NexusLoginManager : ViewModel, INeedsLogin
|
||||
[Reactive]
|
||||
public bool HaveLogin { get; set; }
|
||||
|
||||
public NexusLoginManager(ILogger<NexusLoginManager> logger, ITokenProvider<NexusApiState> token)
|
||||
public NexusLoginManager(ILogger<NexusLoginManager> logger, ITokenProvider<NexusApiState> token, IServiceProvider serviceProvider)
|
||||
{
|
||||
_logger = logger;
|
||||
_token = token;
|
||||
_serviceProvider = serviceProvider;
|
||||
RefreshTokenState();
|
||||
|
||||
ClearLogin = ReactiveCommand.CreateFromTask(async () =>
|
||||
@ -45,10 +51,13 @@ public class NexusLoginManager : ViewModel, INeedsLogin
|
||||
|
||||
TriggerLogin = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
_logger.LogInformation("Logging into {SiteName}", SiteName);
|
||||
await NexusLogin.Send();
|
||||
RefreshTokenState();
|
||||
_logger.LogInformation("Logging into {SiteName}", SiteName);
|
||||
MessageBus.Current.SendMessage(new OpenBrowserTab(_serviceProvider.GetRequiredService<NexusLoginHandler>()));
|
||||
}, this.WhenAnyValue(v => v.HaveLogin).Select(v => !v));
|
||||
|
||||
MessageBus.Current.Listen<CloseBrowserTab>()
|
||||
.Subscribe(x => RefreshTokenState())
|
||||
.DisposeWith(CompositeDisposable);
|
||||
}
|
||||
|
||||
private void RefreshTokenState()
|
||||
|
11
Wabbajack.App.Wpf/Messages/CloseBrowserTab.cs
Normal file
11
Wabbajack.App.Wpf/Messages/CloseBrowserTab.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace Wabbajack.Messages;
|
||||
|
||||
public class CloseBrowserTab
|
||||
{
|
||||
public BrowserTabViewModel ViewModel { get; init; }
|
||||
|
||||
public CloseBrowserTab(BrowserTabViewModel viewModel)
|
||||
{
|
||||
ViewModel = viewModel;
|
||||
}
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Models;
|
||||
using Wabbajack.Networking.Http.Interfaces;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.UserIntervention;
|
||||
|
||||
public class LoversLabLoginHandler : OAuth2LoginHandler<Messages.LoversLabLogin, DTOs.Logins.LoversLabLoginState>
|
||||
{
|
||||
public LoversLabLoginHandler(ILogger<LoversLabLoginHandler> logger, HttpClient client, ITokenProvider<DTOs.Logins.LoversLabLoginState> tokenProvider,
|
||||
WebBrowserVM browser, CefService service)
|
||||
: base(logger, client, tokenProvider, browser, service)
|
||||
public LoversLabLoginHandler(ILogger<LoversLabLoginHandler> logger, HttpClient httpClient, EncryptedJsonTokenProvider<LoversLabLoginState> tokenProvider)
|
||||
: base(logger, httpClient, tokenProvider)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,104 +1,98 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Fizzler.Systems.HtmlAgilityPack;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.Models;
|
||||
using Wabbajack.Networking.Http.Interfaces;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.UserIntervention;
|
||||
|
||||
public class NexusLoginHandler : WebUserInterventionBase<NexusLogin>
|
||||
public class NexusLoginHandler : BrowserTabViewModel
|
||||
{
|
||||
private readonly ITokenProvider<NexusApiState> _provider;
|
||||
private readonly EncryptedJsonTokenProvider<NexusApiState> _tokenProvider;
|
||||
|
||||
public NexusLoginHandler(ILogger<NexusLoginHandler> logger, WebBrowserVM browserVM, ITokenProvider<NexusApiState> provider, CefService service)
|
||||
: base(logger, browserVM, service)
|
||||
public NexusLoginHandler(EncryptedJsonTokenProvider<NexusApiState> tokenProvider)
|
||||
{
|
||||
_provider = provider;
|
||||
HeaderText = "Nexus Login";
|
||||
_tokenProvider = tokenProvider;
|
||||
}
|
||||
public override async Task Begin()
|
||||
|
||||
protected override async Task Run(CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
Messages.NavigateTo.Send(Browser);
|
||||
UpdateStatus("Please log into the Nexus");
|
||||
await Driver.WaitForInitialized();
|
||||
|
||||
await NavigateTo(new Uri("https://users.nexusmods.com/auth/continue?client_id=nexus&redirect_uri=https://www.nexusmods.com/oauth/callback&response_type=code&referrer=//www.nexusmods.com"));
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
Cookie[] cookies = {};
|
||||
while (true)
|
||||
Instructions = "Please log into the Nexus";
|
||||
|
||||
await NavigateTo(new Uri(
|
||||
"https://users.nexusmods.com/auth/continue?client_id=nexus&redirect_uri=https://www.nexusmods.com/oauth/callback&response_type=code&referrer=//www.nexusmods.com"));
|
||||
|
||||
|
||||
Cookie[] cookies = { };
|
||||
while (true)
|
||||
{
|
||||
cookies = await GetCookies("nexusmods.com", token);
|
||||
if (cookies.Any(c => c.Name == "member_id"))
|
||||
break;
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
await Task.Delay(500, token);
|
||||
}
|
||||
|
||||
Instructions = "Getting API Key...";
|
||||
|
||||
await NavigateTo(new Uri("https://www.nexusmods.com/users/myaccount?tab=api"));
|
||||
|
||||
var key = "";
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
cookies = await Driver.GetCookies("nexusmods.com");
|
||||
if (cookies.Any(c => c.Name == "member_id"))
|
||||
break;
|
||||
Message.Token.ThrowIfCancellationRequested();
|
||||
await Task.Delay(500, Message.Token);
|
||||
key = (await GetDom(token))
|
||||
.DocumentNode
|
||||
.QuerySelectorAll("input[value=wabbajack]")
|
||||
.SelectMany(p => p.ParentNode.ParentNode.QuerySelectorAll("textarea.application-key"))
|
||||
.Select(node => node.InnerHtml)
|
||||
.FirstOrDefault() ?? "";
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
break;
|
||||
|
||||
await NavigateTo(new Uri("https://www.nexusmods.com/users/myaccount?tab=api"));
|
||||
|
||||
UpdateStatus("Looking for API Key");
|
||||
|
||||
var key = "";
|
||||
|
||||
while (true)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
key = await Driver.EvaluateJavaScript(
|
||||
"document.querySelector(\"input[value=wabbajack]\").parentElement.parentElement.querySelector(\"textarea.application-key\").innerHTML");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Driver.EvaluateJavaScript(
|
||||
"var found = document.querySelector(\"input[value=wabbajack]\").parentElement.parentElement.querySelector(\"form button[type=submit]\");" +
|
||||
"found.onclick= function() {return true;};" +
|
||||
"found.class = \" \"; " +
|
||||
"found.click();" +
|
||||
"found.remove(); found = undefined;"
|
||||
);
|
||||
UpdateStatus("Generating API Key, Please Wait...");
|
||||
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Message.Token.ThrowIfCancellationRequested();
|
||||
await Task.Delay(500, Message.Token);
|
||||
await EvaluateJavaScript(
|
||||
"var found = document.querySelector(\"input[value=wabbajack]\").parentElement.parentElement.querySelector(\"form button[type=submit]\");" +
|
||||
"found.onclick= function() {return true;};" +
|
||||
"found.class = \" \"; " +
|
||||
"found.click();" +
|
||||
"found.remove(); found = undefined;"
|
||||
);
|
||||
Instructions = "Generating API Key, Please Wait...";
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
|
||||
await _provider.SetToken(new NexusApiState()
|
||||
{
|
||||
ApiKey = key,
|
||||
Cookies = cookies
|
||||
});
|
||||
|
||||
((NexusLogin)Message).CompletionSource.SetResult();
|
||||
Messages.NavigateTo.Send(PrevPane);
|
||||
token.ThrowIfCancellationRequested();
|
||||
await Task.Delay(500, token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
Instructions = "Success, saving information...";
|
||||
await _tokenProvider.SetToken(new NexusApiState
|
||||
{
|
||||
Logger.LogError(ex, "While logging into Nexus Mods");
|
||||
Message.SetException(ex);
|
||||
Messages.NavigateTo.Send(PrevPane);
|
||||
}
|
||||
Cookies = cookies,
|
||||
ApiKey = key
|
||||
});
|
||||
}
|
||||
}
|
@ -22,45 +22,57 @@ public abstract class OAuth2LoginHandler<TIntervention, TLoginType> : WebUserInt
|
||||
where TLoginType : OAuth2LoginState, new()
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ITokenProvider<TLoginType> _tokenProvider;
|
||||
private readonly EncryptedJsonTokenProvider<TLoginType> _tokenProvider;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public OAuth2LoginHandler(ILogger logger, HttpClient httpClient,
|
||||
ITokenProvider<TLoginType> tokenProvider, WebBrowserVM browserVM, CefService service) : base(logger, browserVM, service)
|
||||
EncryptedJsonTokenProvider<TLoginType> tokenProvider)
|
||||
{
|
||||
var tlogin = new TLoginType();
|
||||
HeaderText = $"{tlogin.SiteName} Login";
|
||||
_logger = logger;
|
||||
_httpClient = httpClient;
|
||||
_tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
public override async Task Begin()
|
||||
protected override async Task Run(CancellationToken token)
|
||||
{
|
||||
Messages.NavigateTo.Send(Browser);
|
||||
var tlogin = new TLoginType();
|
||||
|
||||
await Driver.WaitForInitialized();
|
||||
|
||||
using var handler = Driver.WithSchemeHandler(uri => uri.Scheme == "wabbajack");
|
||||
|
||||
UpdateStatus($"Please log in and allow Wabbajack to access your {tlogin.SiteName} account");
|
||||
var tcs = new TaskCompletionSource<Uri>();
|
||||
await WaitForReady();
|
||||
Browser!.Browser.CoreWebView2.Settings.UserAgent = "Wabbajack";
|
||||
Browser!.Browser.NavigationStarting += (sender, args) =>
|
||||
{
|
||||
var uri = new Uri(args.Uri);
|
||||
if (uri.Scheme == "wabbajack")
|
||||
{
|
||||
tcs.TrySetResult(uri);
|
||||
}
|
||||
};
|
||||
|
||||
Instructions = $"Please log in and allow Wabbajack to access your {tlogin.SiteName} account";
|
||||
|
||||
var scopes = string.Join(" ", tlogin.Scopes);
|
||||
var state = Guid.NewGuid().ToString();
|
||||
|
||||
await NavigateTo(new Uri(tlogin.AuthorizationEndpoint + $"?response_type=code&client_id={tlogin.ClientID}&state={state}&scope={scopes}"));
|
||||
await NavigateTo(new Uri(tlogin.AuthorizationEndpoint +
|
||||
$"?response_type=code&client_id={tlogin.ClientID}&state={state}&scope={scopes}"));
|
||||
|
||||
var uri = await handler.Task.WaitAsync(Message.Token);
|
||||
var uri = await tcs.Task.WaitAsync(token);
|
||||
|
||||
var cookies = await Driver.GetCookies(tlogin.AuthorizationEndpoint.Host);
|
||||
var cookies = await GetCookies(tlogin.AuthorizationEndpoint.Host, token);
|
||||
|
||||
var parsed = HttpUtility.ParseQueryString(uri.Query);
|
||||
if (parsed.Get("state") != state)
|
||||
{
|
||||
Logger.LogCritical("Bad OAuth state, this shouldn't happen");
|
||||
_logger.LogCritical("Bad OAuth state, this shouldn't happen");
|
||||
throw new Exception("Bad OAuth State");
|
||||
}
|
||||
|
||||
if (parsed.Get("code") == null)
|
||||
{
|
||||
Logger.LogCritical("Bad code result from OAuth");
|
||||
_logger.LogCritical("Bad code result from OAuth");
|
||||
throw new Exception("Bad code result from OAuth");
|
||||
}
|
||||
|
||||
@ -81,8 +93,8 @@ public abstract class OAuth2LoginHandler<TIntervention, TLoginType> : WebUserInt
|
||||
msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
|
||||
msg.Content = new FormUrlEncodedContent(formData.ToList());
|
||||
|
||||
using var response = await _httpClient.SendAsync(msg, Message.Token);
|
||||
var data = await response.Content.ReadFromJsonAsync<OAuthResultState>(cancellationToken: Message.Token);
|
||||
using var response = await _httpClient.SendAsync(msg, token);
|
||||
var data = await response.Content.ReadFromJsonAsync<OAuthResultState>(cancellationToken: token);
|
||||
|
||||
await _tokenProvider.SetToken(new TLoginType
|
||||
{
|
||||
@ -90,6 +102,5 @@ public abstract class OAuth2LoginHandler<TIntervention, TLoginType> : WebUserInt
|
||||
ResultState = data!
|
||||
});
|
||||
|
||||
Messages.NavigateTo.Send(PrevPane);
|
||||
}
|
||||
}
|
@ -1,15 +1,16 @@
|
||||
using System.Net.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Models;
|
||||
using Wabbajack.Networking.Http.Interfaces;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.UserIntervention;
|
||||
|
||||
public class VectorPlexusLoginHandler : OAuth2LoginHandler<Messages.VectorPlexusLogin, DTOs.Logins.VectorPlexusLoginState>
|
||||
{
|
||||
public VectorPlexusLoginHandler(ILogger<VectorPlexusLoginHandler> logger, HttpClient client, ITokenProvider<DTOs.Logins.VectorPlexusLoginState> tokenProvider,
|
||||
WebBrowserVM browser, CefService service)
|
||||
: base(logger, client, tokenProvider, browser, service)
|
||||
public VectorPlexusLoginHandler(ILogger<VectorPlexusLoginHandler> logger, HttpClient httpClient, EncryptedJsonTokenProvider<VectorPlexusLoginState> tokenProvider)
|
||||
: base(logger, httpClient, tokenProvider)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,46 +1,99 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using HtmlAgilityPack;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.Wpf;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Interventions;
|
||||
using Wabbajack.Models;
|
||||
using Wabbajack.Views;
|
||||
using Wabbajack.WebAutomation;
|
||||
|
||||
namespace Wabbajack.UserIntervention;
|
||||
|
||||
public abstract class WebUserInterventionBase<T>
|
||||
public abstract class WebUserInterventionBase<T> : ViewModel
|
||||
where T : IUserIntervention
|
||||
{
|
||||
protected readonly WebBrowserVM Browser;
|
||||
protected readonly ILogger Logger;
|
||||
protected T Message;
|
||||
protected ViewModel PrevPane;
|
||||
protected IWebDriver Driver;
|
||||
[Reactive]
|
||||
public string HeaderText { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string Instructions { get; set; }
|
||||
|
||||
protected WebUserInterventionBase(ILogger logger, WebBrowserVM browser, CefService service)
|
||||
public BrowserView? Browser { get; set; }
|
||||
|
||||
private WebView2 _browser => Browser!.Browser;
|
||||
|
||||
public async Task RunWrapper(CancellationToken token)
|
||||
{
|
||||
Logger = logger;
|
||||
Browser = browser;
|
||||
//Driver = new CefSharpWrapper(logger, browser.Browser, service);
|
||||
await Run(token);
|
||||
}
|
||||
|
||||
public void Configure(ViewModel prevPane, T message)
|
||||
protected abstract Task Run(CancellationToken token);
|
||||
|
||||
protected async Task WaitForReady()
|
||||
{
|
||||
Message = message;
|
||||
PrevPane = prevPane;
|
||||
while (Browser?.Browser.CoreWebView2 == null)
|
||||
{
|
||||
await Task.Delay(250);
|
||||
}
|
||||
}
|
||||
|
||||
protected void UpdateStatus(string status)
|
||||
public async Task NavigateTo(Uri uri)
|
||||
{
|
||||
Browser.Instructions = status;
|
||||
var tcs = new TaskCompletionSource();
|
||||
|
||||
void Completed(object? o, CoreWebView2NavigationCompletedEventArgs a)
|
||||
{
|
||||
if (a.IsSuccess)
|
||||
{
|
||||
tcs.TrySetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
tcs.TrySetException(new Exception($"Navigation error to {uri}"));
|
||||
}
|
||||
}
|
||||
|
||||
_browser.NavigationCompleted += Completed;
|
||||
_browser.Source = uri;
|
||||
await tcs.Task;
|
||||
_browser.NavigationCompleted -= Completed;
|
||||
}
|
||||
|
||||
public async Task<Cookie[]> GetCookies(string domainEnding, CancellationToken token)
|
||||
{
|
||||
var cookies = (await _browser.CoreWebView2.CookieManager.GetCookiesAsync(""))
|
||||
.Where(c => c.Domain.EndsWith(domainEnding));
|
||||
return cookies.Select(c => new Cookie
|
||||
{
|
||||
Domain = c.Domain,
|
||||
Name = c.Name,
|
||||
Path = c.Path,
|
||||
Value = c.Value
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
protected async Task NavigateTo(Uri uri)
|
||||
public async Task<string> EvaluateJavaScript(string js)
|
||||
{
|
||||
await Driver.NavigateTo(uri, Message.Token);
|
||||
return await _browser.ExecuteScriptAsync(js);
|
||||
}
|
||||
|
||||
public abstract Task Begin();
|
||||
public async Task<HtmlDocument> GetDom(CancellationToken token)
|
||||
{
|
||||
var v = HttpUtility.UrlDecode("\u003D");
|
||||
var source = await EvaluateJavaScript("document.body.outerHTML");
|
||||
var decoded = JsonSerializer.Deserialize<string>(source);
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(decoded);
|
||||
return doc;
|
||||
}
|
||||
|
||||
}
|
@ -7,8 +7,10 @@ using System.Web;
|
||||
using HtmlAgilityPack;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.Wpf;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.Views;
|
||||
|
||||
namespace Wabbajack;
|
||||
@ -26,6 +28,7 @@ public abstract class BrowserTabViewModel : ViewModel
|
||||
public async Task RunWrapper(CancellationToken token)
|
||||
{
|
||||
await Run(token);
|
||||
MessageBus.Current.SendMessage(new CloseBrowserTab(this));
|
||||
}
|
||||
|
||||
protected abstract Task Run(CancellationToken token);
|
||||
|
@ -8,6 +8,7 @@ using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
@ -164,22 +165,20 @@ namespace Wabbajack
|
||||
private void HandleLogin(NexusLogin nexusLogin)
|
||||
{
|
||||
var handler = _serviceProvider.GetRequiredService<NexusLoginHandler>();
|
||||
handler.Configure(ActivePane, nexusLogin);
|
||||
handler.Begin().FireAndForget();
|
||||
handler.RunWrapper(CancellationToken.None).FireAndForget();
|
||||
}
|
||||
|
||||
private void HandleLogin(LoversLabLogin loversLabLogin)
|
||||
{
|
||||
var handler = _serviceProvider.GetRequiredService<LoversLabLoginHandler>();
|
||||
handler.Configure(ActivePane, loversLabLogin);
|
||||
handler.Begin().FireAndForget();
|
||||
handler.RunWrapper(CancellationToken.None).FireAndForget();
|
||||
}
|
||||
|
||||
private void HandleLogin(VectorPlexusLogin vectorPlexusLogin)
|
||||
{
|
||||
var handler = _serviceProvider.GetRequiredService<VectorPlexusLoginHandler>();
|
||||
handler.Configure(ActivePane, vectorPlexusLogin);
|
||||
handler.Begin().FireAndForget();
|
||||
handler.RunWrapper(CancellationToken.None).FireAndForget();
|
||||
|
||||
}
|
||||
|
||||
private void HandleNavigateBack(NavigateBack navigateBack)
|
||||
|
@ -44,7 +44,8 @@ public partial class BrowserTabView : IDisposable
|
||||
private void ClickClose(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var tc = (TabControl) this.Parent;
|
||||
tc.Items.Remove(this);
|
||||
if (tc.Items.Contains(this))
|
||||
tc.Items.Remove(this);
|
||||
this.Dispose();
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,10 @@
|
||||
<TabControl Grid.Row="0" x:Name="Tabs">
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock FontSize="16" Margin="0, 0, 8, 0">WABBAJACK 3.0.0</TextBlock>
|
||||
<Button Name="SettingsButton"><icon:Material Kind="Cog"></icon:Material></Button>
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
|
||||
<Grid>
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@ -51,6 +52,12 @@ namespace Wabbajack
|
||||
TaskbarItemInfo.ProgressState = u.State;
|
||||
});
|
||||
|
||||
MessageBus.Current.Listen<OpenBrowserTab>()
|
||||
.Subscribe(OnOpenBrowserTab);
|
||||
|
||||
MessageBus.Current.Listen<CloseBrowserTab>()
|
||||
.Subscribe(OnCloseBrowserTab);
|
||||
|
||||
_logger.LogInformation("Wabbajack Build - {Sha}",ThisAssembly.Git.Sha);
|
||||
_logger.LogInformation("Running in {EntryPoint}", KnownFolders.EntryPoint);
|
||||
|
||||
@ -97,6 +104,9 @@ namespace Wabbajack
|
||||
{
|
||||
this.Topmost = false;
|
||||
};
|
||||
|
||||
((MainWindowVM) DataContext).WhenAnyValue(vm => vm.OpenSettingsCommand)
|
||||
.BindTo(this, view => view.SettingsButton.Command);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -196,5 +206,15 @@ namespace Wabbajack
|
||||
Tabs.Items.Add(tab);
|
||||
Tabs.SelectedItem = tab;
|
||||
}
|
||||
|
||||
private void OnCloseBrowserTab(CloseBrowserTab msg)
|
||||
{
|
||||
foreach (var tab in Tabs.Items.OfType<BrowserTabView>())
|
||||
{
|
||||
if (tab.DataContext != msg.ViewModel) continue;
|
||||
Tabs.Items.Remove(tab);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.1.0">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" />
|
||||
<PackageReference Include="Fody" Version="6.5.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@ -76,7 +77,7 @@
|
||||
<PackageReference Include="MahApps.Metro.IconPacks" Version="4.8.0" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1189-prerelease" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1248-prerelease" />
|
||||
<PackageReference Include="PInvoke.User32" Version="0.7.104" />
|
||||
<PackageReference Include="ReactiveUI" Version="16.2.6" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="16.2.6" />
|
||||
|
Loading…
Reference in New Issue
Block a user