Merge pull request #300 from wabbajack-tools/login-manager

Login manager
This commit is contained in:
Timothy Baldridge
2019-12-21 14:43:23 -08:00
committed by GitHub
16 changed files with 363 additions and 24 deletions

View File

@ -5,6 +5,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Reactive.Linq;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -39,14 +40,32 @@ namespace Wabbajack.Common
} }
public static string LogFile { get; private set; } public static string LogFile { get; private set; }
public enum FileEventType
{
Created,
Changed,
Deleted
}
static Utils() static Utils()
{ {
if (!Directory.Exists(Consts.LocalAppDataPath))
Directory.CreateDirectory(Consts.LocalAppDataPath);
var programName = Assembly.GetEntryAssembly()?.Location ?? "Wabbajack"; var programName = Assembly.GetEntryAssembly()?.Location ?? "Wabbajack";
LogFile = programName + ".log"; LogFile = programName + ".log";
_startTime = DateTime.Now; _startTime = DateTime.Now;
if (LogFile.FileExists()) if (LogFile.FileExists())
File.Delete(LogFile); File.Delete(LogFile);
var watcher = new FileSystemWatcher(Consts.LocalAppDataPath);
AppLocalEvents = Observable.Merge(Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(h => watcher.Changed += h, h => watcher.Changed -= h).Select(e => (FileEventType.Changed, e.EventArgs)),
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(h => watcher.Created += h, h => watcher.Created -= h).Select(e => (FileEventType.Created, e.EventArgs)),
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(h => watcher.Deleted += h, h => watcher.Deleted -= h).Select(e => (FileEventType.Deleted, e.EventArgs)))
.ObserveOn(RxApp.TaskpoolScheduler);
watcher.EnableRaisingEvents = true;
} }
private static readonly Subject<IStatusMessage> LoggerSubj = new Subject<IStatusMessage>(); private static readonly Subject<IStatusMessage> LoggerSubj = new Subject<IStatusMessage>();
@ -999,12 +1018,37 @@ namespace Wabbajack.Common
public static T FromEncryptedJson<T>(string key) public static T FromEncryptedJson<T>(string key)
{ {
var path = Path.Combine(KnownFolders.LocalAppData.Path, "Wabbajack", key); var path = Path.Combine(Consts.LocalAppDataPath, key);
var bytes = File.ReadAllBytes(path); var bytes = File.ReadAllBytes(path);
var decoded = ProtectedData.Unprotect(bytes, Encoding.UTF8.GetBytes(key), DataProtectionScope.LocalMachine); var decoded = ProtectedData.Unprotect(bytes, Encoding.UTF8.GetBytes(key), DataProtectionScope.LocalMachine);
return Encoding.UTF8.GetString(decoded).FromJSONString<T>(); return Encoding.UTF8.GetString(decoded).FromJSONString<T>();
} }
public static bool HaveEncryptedJson(string key)
{
var path = Path.Combine(Consts.LocalAppDataPath, key);
return File.Exists(path);
}
public static IObservable<(FileEventType, FileSystemEventArgs)> AppLocalEvents { get; }
public static IObservable<bool> HaveEncryptedJsonObservable(string key)
{
var path = Path.Combine(Consts.LocalAppDataPath, key).ToLower();
return AppLocalEvents.Where(t => t.Item2.FullPath.ToLower() == path)
.Select(_ => File.Exists(path))
.StartWith(File.Exists(path))
.DistinctUntilChanged();
}
public static void DeleteEncryptedJson(string key)
{
var path = Path.Combine(Consts.LocalAppDataPath, key);
if (File.Exists(path))
File.Delete(path);
}
public static bool IsInPath(this string path, string parent) public static bool IsInPath(this string path, string parent)
{ {
return path.ToLower().TrimEnd('\\').StartsWith(parent.ToLower().TrimEnd('\\') + "\\"); return path.ToLower().TrimEnd('\\').StartsWith(parent.ToLower().TrimEnd('\\') + "\\");

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Wabbajack.Lib.Downloaders
{
public interface INeedsLogin : INotifyPropertyChanged
{
ICommand TriggerLogin { get; }
ICommand ClearLogin { get; }
IObservable<bool> IsLoggedIn { get; }
string SiteName { get; }
string MetaInfo { get; }
Uri SiteURL { get; }
Uri IconUri { get; }
}
}

View File

@ -4,22 +4,47 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Reactive.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Windows.Input;
using ReactiveUI;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Lib.LibCefHelpers; using Wabbajack.Lib.LibCefHelpers;
using Wabbajack.Lib.NexusApi;
using Wabbajack.Lib.Validation; using Wabbajack.Lib.Validation;
using Xilium.CefGlue.Common; using Xilium.CefGlue.Common;
using File = Alphaleonis.Win32.Filesystem.File; using File = Alphaleonis.Win32.Filesystem.File;
namespace Wabbajack.Lib.Downloaders namespace Wabbajack.Lib.Downloaders
{ {
public class LoversLabDownloader : IDownloader public class LoversLabDownloader : ViewModel, IDownloader, INeedsLogin
{ {
internal HttpClient _authedClient; internal HttpClient _authedClient;
#region INeedsDownload
public ICommand TriggerLogin { get; }
public ICommand ClearLogin { get; }
public IObservable<bool> IsLoggedIn => Utils.HaveEncryptedJsonObservable("loverslabcookies");
public string SiteName => "Lovers Lab";
public string MetaInfo => "";
public Uri SiteURL => new Uri("https://loverslab.com");
public Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico");
#endregion
public LoversLabDownloader()
{
TriggerLogin = ReactiveCommand.Create(async () => await Utils.Log(new RequestLoversLabLogin()).Task, IsLoggedIn.Select(b => !b).ObserveOn(RxApp.MainThreadScheduler));
ClearLogin = ReactiveCommand.Create(() => Utils.DeleteEncryptedJson("loverslabcookies"), IsLoggedIn.ObserveOn(RxApp.MainThreadScheduler));
}
public async Task<AbstractDownloadState> GetDownloaderState(dynamic archive_ini) public async Task<AbstractDownloadState> GetDownloaderState(dynamic archive_ini)
{ {
Uri url = DownloaderUtils.GetDirectURL(archive_ini); Uri url = DownloaderUtils.GetDirectURL(archive_ini);
@ -84,7 +109,7 @@ namespace Wabbajack.Lib.Downloaders
} }
catch (FileNotFoundException) { } catch (FileNotFoundException) { }
cookies = Utils.Log(new RequestLoversLabLogin()).Task.Result; cookies = await Utils.Log(new RequestLoversLabLogin()).Task;
return Helpers.GetClient(cookies, "https://www.loverslab.com"); return Helpers.GetClient(cookies, "https://www.loverslab.com");
} }
@ -176,6 +201,7 @@ namespace Wabbajack.Lib.Downloaders
return $"* Lovers Lab - [{a.Name}](https://www.loverslab.com/files/file/{FileName}/?do=download&r={FileID})"; return $"* Lovers Lab - [{a.Name}](https://www.loverslab.com/files/file/{FileName}/?do=download&r={FileID})";
} }
} }
} }
public class RequestLoversLabLogin : AUserIntervention public class RequestLoversLabLogin : AUserIntervention

View File

@ -1,7 +1,11 @@
using System; using System;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Reactive.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input;
using ReactiveUI;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Common.StatusFeed.Errors; using Wabbajack.Common.StatusFeed.Errors;
using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.NexusApi;
@ -9,13 +13,39 @@ using Wabbajack.Lib.Validation;
namespace Wabbajack.Lib.Downloaders namespace Wabbajack.Lib.Downloaders
{ {
public class NexusDownloader : IDownloader public class NexusDownloader : ViewModel, IDownloader, INeedsLogin
{ {
private bool _prepared; private bool _prepared;
private SemaphoreSlim _lock = new SemaphoreSlim(1); private SemaphoreSlim _lock = new SemaphoreSlim(1);
private UserStatus _status; private UserStatus _status;
private NexusApiClient _client; private NexusApiClient _client;
public NexusDownloader()
{
TriggerLogin = ReactiveCommand.Create(async () => await NexusApiClient.RequestAndCacheAPIKey(), IsLoggedIn.Select(b => !b).ObserveOn(RxApp.MainThreadScheduler));
ClearLogin = ReactiveCommand.Create(() => Utils.DeleteEncryptedJson("nexusapikey"), IsLoggedIn.ObserveOn(RxApp.MainThreadScheduler));
}
public IObservable<bool> IsLoggedIn => Utils.HaveEncryptedJsonObservable("nexusapikey");
public string SiteName => "Nexus Mods";
public string MetaInfo
{
get
{
return "";
}
}
public Uri SiteURL => new Uri("https://www.nexusmods.com");
public Uri IconUri => new Uri("https://www.nexusmods.com/favicon.ico");
public ICommand TriggerLogin { get; }
public ICommand ClearLogin { get; }
public async Task<AbstractDownloadState> GetDownloaderState(dynamic archiveINI) public async Task<AbstractDownloadState> GetDownloaderState(dynamic archiveINI)
{ {
var general = archiveINI?.General; var general = archiveINI?.General;

View File

@ -89,9 +89,7 @@ namespace Wabbajack.Lib.NexusApi
return env_key; return env_key;
} }
var result = await Utils.Log(new RequestNexusAuthorization()).Task; return await RequestAndCacheAPIKey();
result.ToEcryptedJson("nexusapikey");
return result;
} }
finally finally
{ {
@ -99,6 +97,13 @@ namespace Wabbajack.Lib.NexusApi
} }
} }
public static async Task<string> RequestAndCacheAPIKey()
{
var result = await Utils.Log(new RequestNexusAuthorization()).Task;
result.ToEcryptedJson("nexusapikey");
return result;
}
class RefererHandler : RequestHandler class RefererHandler : RequestHandler
{ {
private string _referer; private string _referer;

View File

@ -116,6 +116,7 @@
<Compile Include="CompilationSteps\PatchStockESMs.cs" /> <Compile Include="CompilationSteps\PatchStockESMs.cs" />
<Compile Include="CompilationSteps\Serialization.cs" /> <Compile Include="CompilationSteps\Serialization.cs" />
<Compile Include="Downloaders\GameFileSourceDownloader.cs" /> <Compile Include="Downloaders\GameFileSourceDownloader.cs" />
<Compile Include="Downloaders\INeedsLogin.cs" />
<Compile Include="Downloaders\LoversLabDownloader.cs" /> <Compile Include="Downloaders\LoversLabDownloader.cs" />
<Compile Include="Downloaders\SteamWorkshopDownloader.cs" /> <Compile Include="Downloaders\SteamWorkshopDownloader.cs" />
<Compile Include="Extensions\ReactiveUIExt.cs" /> <Compile Include="Extensions\ReactiveUIExt.cs" />

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wabbajack.Common;
namespace Wabbajack.UserInterventions
{
public class ShowLoginManager : AUserIntervention
{
public override string ShortDescription => "User requested to show the login manager";
public override string ExtendedDescription => "User requested to show the UI for managing all the logins supported by Wabbajack";
public override void Cancel()
{
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using ReactiveUI;
using Wabbajack.Lib;
using Wabbajack.Lib.Downloaders;
namespace Wabbajack
{
public class LoginManagerVM : ViewModel
{
private MainWindowVM mainWindowVM;
public ICommand BackCommand { get; }
public List<INeedsLogin> Downloaders { get; }
public LoginManagerVM(MainWindowVM mainWindowVM)
{
BackCommand = ReactiveCommand.Create(() => mainWindowVM.NavigateBack());
Downloaders = DownloadDispatcher.Downloaders.OfType<INeedsLogin>().ToList();
}
}
}

View File

@ -3,6 +3,7 @@ using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reactive.Disposables; using System.Reactive.Disposables;
@ -37,9 +38,17 @@ namespace Wabbajack
public readonly Lazy<ModListGalleryVM> Gallery; public readonly Lazy<ModListGalleryVM> Gallery;
public readonly ModeSelectionVM ModeSelectionVM; public readonly ModeSelectionVM ModeSelectionVM;
public readonly UserInterventionHandlers UserInterventionHandlers; public readonly UserInterventionHandlers UserInterventionHandlers;
public readonly LoginManagerVM LoginManagerVM;
public readonly List<ViewModel> NavigationTrail = new List<ViewModel>();
public Dispatcher ViewDispatcher { get; set; } public Dispatcher ViewDispatcher { get; set; }
public ICommand CopyVersionCommand { get; } public ICommand CopyVersionCommand { get; }
public ICommand ShowLoginManagerVM { get; }
public ICommand GoBackCommand { get; }
public string VersionDisplay { get; } public string VersionDisplay { get; }
public MainWindowVM(MainWindow mainWindow, MainSettings settings) public MainWindowVM(MainWindow mainWindow, MainSettings settings)
@ -52,6 +61,7 @@ namespace Wabbajack
Gallery = new Lazy<ModListGalleryVM>(() => new ModListGalleryVM(this)); Gallery = new Lazy<ModListGalleryVM>(() => new ModListGalleryVM(this));
ModeSelectionVM = new ModeSelectionVM(this); ModeSelectionVM = new ModeSelectionVM(this);
UserInterventionHandlers = new UserInterventionHandlers(this); UserInterventionHandlers = new UserInterventionHandlers(this);
LoginManagerVM = new LoginManagerVM(this);
// Set up logging // Set up logging
Utils.LogMessages Utils.LogMessages
@ -99,7 +109,6 @@ namespace Wabbajack
Clipboard.SetText($"Wabbajack {VersionDisplay}\n{ThisAssembly.Git.Sha}"); Clipboard.SetText($"Wabbajack {VersionDisplay}\n{ThisAssembly.Git.Sha}");
}); });
} }
private static bool IsStartingFromModlist(out string modlistPath) private static bool IsStartingFromModlist(out string modlistPath)
{ {
string[] args = Environment.GetCommandLineArgs(); string[] args = Environment.GetCommandLineArgs();
@ -113,6 +122,7 @@ namespace Wabbajack
return true; return true;
} }
public void OpenInstaller(string path) public void OpenInstaller(string path)
{ {
if (path == null) return; if (path == null) return;
@ -122,6 +132,19 @@ namespace Wabbajack
installer.ModListLocation.TargetPath = path; installer.ModListLocation.TargetPath = path;
} }
public void NavigateBack()
{
var prev = NavigationTrail.Last();
NavigationTrail.RemoveAt(NavigationTrail.Count - 1);
ActivePane = prev;
}
public void NavigateTo(ViewModel vm)
{
NavigationTrail.Add(ActivePane);
ActivePane = vm;
}
public void ShutdownApplication() public void ShutdownApplication()
{ {
Dispose(); Dispose();

View File

@ -10,6 +10,7 @@ using ReactiveUI;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Lib.Downloaders; using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.NexusApi;
using Wabbajack.UserInterventions;
namespace Wabbajack namespace Wabbajack
{ {
@ -72,9 +73,14 @@ namespace Wabbajack
break; break;
case ConfirmationIntervention c: case ConfirmationIntervention c:
break; break;
case ShowLoginManager c:
MainWindow.NavigateTo(MainWindow.LoginManagerVM);
break;
default: default:
throw new NotImplementedException($"No handler for {msg}"); throw new NotImplementedException($"No handler for {msg}");
} }
} }
} }
} }

View File

@ -12,11 +12,23 @@
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Button <Button
Grid.Column="0" Grid.Column="0"
Width="35" Width="35"
Height="35" Height="35"
Click="ConfigureLogins_Click"
Style="{StaticResource IconBareButtonStyle}">
<icon:PackIconMaterial
Width="25"
Height="25"
Kind="Cogs" />
</Button>
<Button
Grid.Column="1"
Width="35"
Height="35"
Click="GitHub_Click" Click="GitHub_Click"
Style="{StaticResource IconBareButtonStyle}"> Style="{StaticResource IconBareButtonStyle}">
<icon:PackIconMaterial <icon:PackIconMaterial
@ -25,7 +37,7 @@
Kind="GithubCircle" /> Kind="GithubCircle" />
</Button> </Button>
<Button <Button
Grid.Column="1" Grid.Column="2"
Width="35" Width="35"
Height="35" Height="35"
Margin="4,0,0,0" Margin="4,0,0,0"
@ -37,7 +49,7 @@
Kind="Patreon" /> Kind="Patreon" />
</Button> </Button>
<Button <Button
Grid.Column="2" Grid.Column="3"
Width="35" Width="35"
Height="35" Height="35"
Click="Discord_Click" Click="Discord_Click"

View File

@ -1,18 +1,8 @@
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using Wabbajack.Common;
using System.Windows.Documents; using Wabbajack.UserInterventions;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wabbajack namespace Wabbajack
{ {
@ -40,5 +30,10 @@ namespace Wabbajack
{ {
Process.Start("https://www.patreon.com/user?u=11907933"); Process.Start("https://www.patreon.com/user?u=11907933");
} }
private void ConfigureLogins_Click(object sender, RoutedEventArgs e)
{
Utils.Log(new ShowLoginManager());
}
} }
} }

View File

@ -0,0 +1,89 @@
<UserControl x:Class="Wabbajack.LoginManagerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:wabbajack="clr-namespace:Wabbajack"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<Color x:Key="TextBackgroundFill">#92000000</Color>
<SolidColorBrush x:Key="TextBackgroundFillBrush" Color="{StaticResource TextBackgroundFill}" />
<Color x:Key="TextBackgroundHoverFill">#DF000000</Color>
<Style x:Key="BackgroundBlurStyle" TargetType="TextBlock">
<Setter Property="Background" Value="{StaticResource TextBackgroundFillBrush}" />
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)"
To="{StaticResource TextBackgroundHoverFill}"
Duration="0:0:0.06" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)"
To="{StaticResource TextBackgroundFill}"
Duration="0:0:0.06" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="47" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<wabbajack:TopProgressView
Title="Login Manager"
Grid.Row="0"
Grid.RowSpan="2"
ShadowMargin="False" />
<Button
x:Name="BackButton"
Grid.Row="0"
Width="30"
Height="30"
Margin="7,5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Command="{Binding BackCommand}"
Style="{StaticResource IconCircleButtonStyle}"
ToolTip="Back to main menu">
<iconPacks:PackIconMaterial Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Kind="ArrowLeft" />
</Button>
<!-- Do it this way so we can access the browser directly from the VM -->
<ListView Grid.Row="1" ItemsSource="{Binding Downloaders}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Height="30" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding IconUrl, Mode=OneTime}"></Image>
<Label Grid.Column="1" Width="400" Content="{Binding SiteName, Mode=OneTime}" FontSize="14"></Label>
<Label Grid.Column="2" Width="400" Content="{Binding MetaInfo, Mode=OneWay}" FontSize="14"></Label>
<Button Grid.Column="3" Content="Login" Command="{Binding TriggerLogin}" Margin="5"></Button>
<Button Grid.Column="4" Content="Logout" Command="{Binding ClearLogin}" Margin="5"></Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for LoginManager.xaml
/// </summary>
public partial class LoginManagerView : UserControl
{
public LoginManagerView()
{
InitializeComponent();
}
}
}

View File

@ -27,6 +27,9 @@
<DataTemplate DataType="{x:Type local:InstallerVM}"> <DataTemplate DataType="{x:Type local:InstallerVM}">
<local:InstallationView /> <local:InstallationView />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type local:LoginManagerVM}">
<local:LoginManagerView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ModeSelectionVM}"> <DataTemplate DataType="{x:Type local:ModeSelectionVM}">
<local:ModeSelectionView /> <local:ModeSelectionView />
</DataTemplate> </DataTemplate>

View File

@ -179,8 +179,10 @@
<Compile Include="UnderMaintenanceOverlay.xaml.cs"> <Compile Include="UnderMaintenanceOverlay.xaml.cs">
<DependentUpon>UnderMaintenanceOverlay.xaml</DependentUpon> <DependentUpon>UnderMaintenanceOverlay.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="UserInterventions\ShowLoginManager.cs" />
<Compile Include="Util\AsyncLazy.cs" /> <Compile Include="Util\AsyncLazy.cs" />
<Compile Include="View Models\CPUDisplayVM.cs" /> <Compile Include="View Models\CPUDisplayVM.cs" />
<Compile Include="View Models\LoginManagerVM.cs" />
<Compile Include="Views\Compilers\CompilationCompleteView.xaml.cs"> <Compile Include="Views\Compilers\CompilationCompleteView.xaml.cs">
<DependentUpon>CompilationCompleteView.xaml</DependentUpon> <DependentUpon>CompilationCompleteView.xaml</DependentUpon>
</Compile> </Compile>
@ -216,6 +218,9 @@
<Compile Include="Views\LinksView.xaml.cs"> <Compile Include="Views\LinksView.xaml.cs">
<DependentUpon>LinksView.xaml</DependentUpon> <DependentUpon>LinksView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\LoginManagerView.xaml.cs">
<DependentUpon>LoginManagerView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ModeSelectionView.xaml.cs"> <Compile Include="Views\ModeSelectionView.xaml.cs">
<DependentUpon>ModeSelectionView.xaml</DependentUpon> <DependentUpon>ModeSelectionView.xaml</DependentUpon>
</Compile> </Compile>
@ -321,6 +326,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\LoginManagerView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ModeSelectionView.xaml"> <Page Include="Views\ModeSelectionView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -496,7 +505,7 @@
<Version>1.6.5</Version> <Version>1.6.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="MahApps.Metro.IconPacks"> <PackageReference Include="MahApps.Metro.IconPacks">
<Version>2.3.0</Version> <Version>3.0.1</Version>
</PackageReference> </PackageReference>
<PackageReference Include="MegaApiClient"> <PackageReference Include="MegaApiClient">
<Version>1.7.1</Version> <Version>1.7.1</Version>