From 6190e3cab92efbcb88978f9d14c639ed8930e3f7 Mon Sep 17 00:00:00 2001 From: affederaffe Date: Wed, 21 Aug 2024 20:11:41 +0200 Subject: [PATCH] Implement Steam download --- .../BeatSaberModManager.csproj | 4 +- .../Resources/Localization/de.axaml | 16 ++- .../Resources/Localization/en.axaml | 16 ++- .../Resources/Styles/Controls.axaml | 1 - .../Steam/SteamLegacyGameVersionInstaller.cs | 8 +- .../LinuxProtocolHandlerRegistrar.cs | 26 +++-- .../ViewModels/GameVersionViewModel.cs | 26 +++-- .../ViewModels/LegacyGameVersionsTab.cs | 38 +++++++ .../ViewModels/LegacyGameVersionsViewModel.cs | 74 +++++++----- .../SteamAuthenticationViewModel.cs | 106 ++++++++++++++---- .../Views/Controls/CardControl.cs | 1 - .../Views/Dialogs/SteamGuardCodeView.axaml | 18 +++ .../Views/Dialogs/SteamGuardCodeView.axaml.cs | 19 ++++ .../Views/Dialogs/SteamLoginView.axaml | 26 +++++ .../Views/Dialogs/SteamLoginView.axaml.cs | 19 ++++ .../Views/Pages/LegacyGameVersionsPage.axaml | 43 ++----- .../Pages/LegacyGameVersionsPage.axaml.cs | 58 ++++++++++ 17 files changed, 376 insertions(+), 123 deletions(-) create mode 100644 BeatSaberModManager/ViewModels/LegacyGameVersionsTab.cs create mode 100644 BeatSaberModManager/Views/Dialogs/SteamGuardCodeView.axaml create mode 100644 BeatSaberModManager/Views/Dialogs/SteamGuardCodeView.axaml.cs create mode 100644 BeatSaberModManager/Views/Dialogs/SteamLoginView.axaml create mode 100644 BeatSaberModManager/Views/Dialogs/SteamLoginView.axaml.cs diff --git a/BeatSaberModManager/BeatSaberModManager.csproj b/BeatSaberModManager/BeatSaberModManager.csproj index 38b90ba..169e767 100644 --- a/BeatSaberModManager/BeatSaberModManager.csproj +++ b/BeatSaberModManager/BeatSaberModManager.csproj @@ -37,7 +37,7 @@ - + @@ -46,7 +46,7 @@ - + diff --git a/BeatSaberModManager/Resources/Localization/de.axaml b/BeatSaberModManager/Resources/Localization/de.axaml index f28ab61..d23edd4 100644 --- a/BeatSaberModManager/Resources/Localization/de.axaml +++ b/BeatSaberModManager/Resources/Localization/de.axaml @@ -76,12 +76,16 @@ Anwendung abgestürzt Ok - Steam Authentifizierung erforderlich - Weiter - Abbrechen - Benutzername - Passwort - Passwort merken + Steam Authentifizierung erforderlich + Login + Abbrechen + Benutzername + Passwort + Passwort merken + + Gib den Code deiner Steam Mobile App ein + Absenden + Cancel Installiere: Deinstalliere: diff --git a/BeatSaberModManager/Resources/Localization/en.axaml b/BeatSaberModManager/Resources/Localization/en.axaml index dd63759..f3c97b7 100644 --- a/BeatSaberModManager/Resources/Localization/en.axaml +++ b/BeatSaberModManager/Resources/Localization/en.axaml @@ -76,12 +76,16 @@ Application Crashed Ok - Steam Authentication Required - Continue - Cancel - Username - Password - Remember Password + Steam Authentication Required + Login + Cancel + Username + Password + Remember Password + + Enter the code from your Steam Mobile App + Submit + Cancel Installing: Uninstalling: diff --git a/BeatSaberModManager/Resources/Styles/Controls.axaml b/BeatSaberModManager/Resources/Styles/Controls.axaml index 0ea5718..6cf4e8b 100644 --- a/BeatSaberModManager/Resources/Styles/Controls.axaml +++ b/BeatSaberModManager/Resources/Styles/Controls.axaml @@ -10,7 +10,6 @@ - diff --git a/BeatSaberModManager/Services/Implementations/GameVersions/Steam/SteamLegacyGameVersionInstaller.cs b/BeatSaberModManager/Services/Implementations/GameVersions/Steam/SteamLegacyGameVersionInstaller.cs index 15ff49b..ada9f66 100644 --- a/BeatSaberModManager/Services/Implementations/GameVersions/Steam/SteamLegacyGameVersionInstaller.cs +++ b/BeatSaberModManager/Services/Implementations/GameVersions/Steam/SteamLegacyGameVersionInstaller.cs @@ -26,8 +26,10 @@ public class SteamLegacyGameVersionInstaller(Steam3Session steam3Session, ISteam return null; string appDataDirPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); string legacyGameVersionsDirPath = Path.Join(appDataDirPath, ThisAssembly.Info.Product, "LegacyGameVersions", gameVersion.GameVersion); - DownloadConfig downloadConfig = new() { InstallDirectory = legacyGameVersionsDirPath }; + DownloadConfig downloadConfig = new() { InstallDirectory = legacyGameVersionsDirPath, MaxDownloads = 3 }; await steam3Session.LoginAsync(steamAuthenticator, cancellationToken).ConfigureAwait(false); + if (cancellationToken.IsCancellationRequested) + return null; ContentDownloader contentDownloader = new(downloadConfig, steam3Session); List<(uint DepotId, ulong ManifestId)> depotManifestIds = [(620981, steamLegacyGameVersion.ManifestId)]; try @@ -35,6 +37,10 @@ public class SteamLegacyGameVersionInstaller(Steam3Session steam3Session, ISteam string[]? installDirs = await contentDownloader.DownloadAppAsync(620980, depotManifestIds, SteamConstants.DefaultBranch, null, null, null, false, false, cancellationToken, progress).ConfigureAwait(false); return installDirs is { Length: 1 } ? installDirs[0] : null; } + catch (TaskCanceledException) + { + return null; + } catch (InvalidOperationException e) { logger.Error(e, "Failed to download depot"); diff --git a/BeatSaberModManager/Services/Implementations/ProtocolHandlerRegistrars/LinuxProtocolHandlerRegistrar.cs b/BeatSaberModManager/Services/Implementations/ProtocolHandlerRegistrars/LinuxProtocolHandlerRegistrar.cs index 9992053..07ae371 100644 --- a/BeatSaberModManager/Services/Implementations/ProtocolHandlerRegistrars/LinuxProtocolHandlerRegistrar.cs +++ b/BeatSaberModManager/Services/Implementations/ProtocolHandlerRegistrars/LinuxProtocolHandlerRegistrar.cs @@ -36,7 +36,7 @@ public bool IsProtocolHandlerRegistered(string protocol) using StreamReader streamReader = new(fileStream); while (streamReader.ReadLine() is { } line) { - if (line.StartsWith($"Exec={Program.Product}", StringComparison.Ordinal)) + if (line.StartsWith($"Exec={ThisAssembly.Info.Product}", StringComparison.Ordinal)) return true; } @@ -65,18 +65,20 @@ public void UnregisterProtocolHandler(string protocol) private string GetHandlerPathForProtocol(string protocol) => Path.Join(_localAppDataPath, GetHandlerNameForProtocol(protocol)); - private static string GetHandlerNameForProtocol(string protocol) => $"{Program.Product}-url-{protocol}.desktop"; + private static string GetHandlerNameForProtocol(string protocol) => $"{ThisAssembly.Info.Product}-url-{protocol}.desktop"; private static string GetDesktopFileContent(string protocol) => - @$"[Desktop Entry] -Name={Program.Product} -Comment=URL:{protocol} Protocol -Type=Application -Categories=Utility -Exec='{Program.Product}' --install %u -Terminal=false -NoDisplay=true -MimeType=x-scheme-handler/{protocol} -"; + $""" + [Desktop Entry] + Name={ThisAssembly.Info.Product} + Comment=URL:{protocol} Protocol + Type=Application + Categories=Utility + Exec='{ThisAssembly.Info.Product}' --install %u + Terminal=false + NoDisplay=true + MimeType=x-scheme-handler/{protocol} + + """; } } diff --git a/BeatSaberModManager/ViewModels/GameVersionViewModel.cs b/BeatSaberModManager/ViewModels/GameVersionViewModel.cs index 6f90ea3..0fa1802 100644 --- a/BeatSaberModManager/ViewModels/GameVersionViewModel.cs +++ b/BeatSaberModManager/ViewModels/GameVersionViewModel.cs @@ -1,6 +1,8 @@ +using System; using System.Reactive.Linq; using BeatSaberModManager.Models.Interfaces; +using BeatSaberModManager.Services.Interfaces; using ReactiveUI; @@ -17,13 +19,14 @@ public sealed class GameVersionViewModel : ViewModelBase /// /// /// - /// - public GameVersionViewModel(IGameVersion gameVersion) + public GameVersionViewModel(IGameVersion gameVersion, IInstallDirValidator installDirValidator) { + ArgumentNullException.ThrowIfNull(installDirValidator); GameVersion = gameVersion; - this.WhenAnyValue(static x => x.GameVersion) - .Select(static x => x is { InstallDir: not null }) - .ToProperty(this, nameof(IsInstalled), out _isInstalled); + this.WhenAnyValue(static x => x.InstallDir) + .Select(installDirValidator.ValidateInstallDir) + .ObserveOn(RxApp.MainThreadScheduler) + .ToProperty(this, static x => x.IsInstalled, out _isInstalled); } /// @@ -36,12 +39,17 @@ public GameVersionViewModel(IGameVersion gameVersion) /// public string? InstallDir { - get => _installDir ??= GameVersion.InstallDir; - set => GameVersion.InstallDir = this.RaiseAndSetIfChanged(ref _installDir, value); + get => GameVersion.InstallDir; + set + { + if (GameVersion.InstallDir == value) + return; + this.RaisePropertyChanging(); + GameVersion.InstallDir = value; + this.RaisePropertyChanged(); + } } - private string? _installDir; - /// /// /// diff --git a/BeatSaberModManager/ViewModels/LegacyGameVersionsTab.cs b/BeatSaberModManager/ViewModels/LegacyGameVersionsTab.cs new file mode 100644 index 0000000..982b36c --- /dev/null +++ b/BeatSaberModManager/ViewModels/LegacyGameVersionsTab.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; + + +namespace BeatSaberModManager.ViewModels +{ + /// + public class LegacyGameVersionsTab : ViewModelBase + { + /// + /// + /// + public LegacyGameVersionsTab(IGrouping group, LegacyGameVersionsViewModel legacyGameVersionsViewModel) + { + ArgumentNullException.ThrowIfNull(group); + Year = group.Key; + Versions = group.ToArray(); + LegacyGameVersionsViewModel = legacyGameVersionsViewModel; + } + + /// + /// + /// + public int Year { get; } + + /// + /// TODO + /// + public IList Versions { get; } + + /// + /// + /// + public LegacyGameVersionsViewModel LegacyGameVersionsViewModel { get; } + + } +} diff --git a/BeatSaberModManager/ViewModels/LegacyGameVersionsViewModel.cs b/BeatSaberModManager/ViewModels/LegacyGameVersionsViewModel.cs index cc29148..b111a64 100644 --- a/BeatSaberModManager/ViewModels/LegacyGameVersionsViewModel.cs +++ b/BeatSaberModManager/ViewModels/LegacyGameVersionsViewModel.cs @@ -14,8 +14,6 @@ using ReactiveUI; -using SteamKit2.Authentication; - namespace BeatSaberModManager.ViewModels { @@ -25,21 +23,23 @@ namespace BeatSaberModManager.ViewModels public sealed class LegacyGameVersionsViewModel : ViewModelBase { private readonly IGameInstallLocator _gameInstallLocator; + private readonly IInstallDirValidator _installDirValidator; private readonly ILegacyGameVersionProvider _legacyGameVersionProvider; private readonly ILegacyGameVersionInstaller _legacyGameVersionInstaller; private readonly ObservableAsPropertyHelper _isExecuting; private readonly ObservableAsPropertyHelper _isSuccess; private readonly ObservableAsPropertyHelper _canInstall; private readonly ObservableAsPropertyHelper _canUninstall; - private readonly ObservableAsPropertyHelper>> _legacyGameVersions; + private readonly ObservableAsPropertyHelper _legacyGameVersions; /// /// TODO /// - public LegacyGameVersionsViewModel(SettingsViewModel settingsViewModel, SteamAuthenticationViewModel steamAuthenticationViewModel, IGameInstallLocator gameInstallLocator, ILegacyGameVersionProvider legacyGameVersionProvider, ILegacyGameVersionInstaller legacyGameVersionInstaller, StatusProgress statusProgress) + public LegacyGameVersionsViewModel(SettingsViewModel settingsViewModel, SteamAuthenticationViewModel steamAuthenticationViewModel, IGameInstallLocator gameInstallLocator, IInstallDirValidator installDirValidator, ILegacyGameVersionProvider legacyGameVersionProvider, ILegacyGameVersionInstaller legacyGameVersionInstaller, StatusProgress statusProgress) { ArgumentNullException.ThrowIfNull(settingsViewModel); _gameInstallLocator = gameInstallLocator; + _installDirValidator = installDirValidator; _legacyGameVersionProvider = legacyGameVersionProvider; _legacyGameVersionInstaller = legacyGameVersionInstaller; SteamAuthenticationViewModel = steamAuthenticationViewModel; @@ -49,22 +49,17 @@ public LegacyGameVersionsViewModel(SettingsViewModel settingsViewModel, SteamAut InitializeCommand.CombineLatest(InitializeCommand.IsExecuting) .Select(static x => x is (not null, false)) .ToProperty(this, nameof(IsSuccess), out _isSuccess); - InitializeCommand.WhereNotNull() - .Select(static gameVersions => gameVersions - .OrderByDescending(static x => x.GameVersion.ReleaseDate) + IObservable legacyGameVersionTabs = InitializeCommand.WhereNotNull() + .Select(gameVersions => gameVersions + .OrderByDescending(static version => version.GameVersion.ReleaseDate) .GroupBy(static version => version.GameVersion.ReleaseDate.Year) - .ToArray()) - .ToProperty(this, nameof(LegacyGameVersions), out _legacyGameVersions); - settingsViewModel.IsGameVersionValidObservable.FirstAsync() - .Where(static isValid => !isValid) - .CombineLatest(InitializeCommand) - .Select(static x => x.Second?.LastOrDefault(static gameVersion => gameVersion.IsInstalled)) - .WhereNotNull() - .Subscribe(installedVersion => settingsViewModel.GameVersion = installedVersion.GameVersion); - settingsViewModel.ValidatedGameVersionObservable.FirstAsync() - .CombineLatest(InitializeCommand.WhereNotNull()) - .Select(static x => x.Second.FirstOrDefault(gameVersion => gameVersion.GameVersion.GameVersion == x.First.GameVersion)) - .Subscribe(gameVersion => SelectedGameVersion = gameVersion); + .Select(group => new LegacyGameVersionsTab(group, this)) + .ToArray()); + legacyGameVersionTabs.ToProperty(this, nameof(LegacyGameVersions), out _legacyGameVersions); + settingsViewModel.ValidatedGameVersionObservable + .FirstAsync() + .CombineLatest(legacyGameVersionTabs) + .Subscribe(x => MarkStoreVersionAsInstalled(x.First, x.Second)); IObservable<(GameVersionViewModel? GameVersion, bool IsInstalled)> whenAnySelectedGameVersion = this.WhenAnyValue(static x => x.SelectedGameVersion, static x => x.SelectedGameVersion!.IsInstalled, static (gameVersion, _) => (gameVersion, gameVersion?.IsInstalled ?? false)); IObservable canInstallVersion = whenAnySelectedGameVersion.Select(static x => x.GameVersion is not null && !x.IsInstalled); canInstallVersion.ToProperty(this, nameof(CanInstall), out _canInstall); @@ -83,11 +78,6 @@ public LegacyGameVersionsViewModel(SettingsViewModel settingsViewModel, SteamAut /// public SteamAuthenticationViewModel SteamAuthenticationViewModel { get; } - /// - /// TODO - /// - public Interaction AuthenticateSteamInteraction { get; } = new(); - /// /// TODO /// @@ -136,7 +126,7 @@ public LegacyGameVersionsViewModel(SettingsViewModel settingsViewModel, SteamAut /// /// TODO /// - public IReadOnlyList> LegacyGameVersions => _legacyGameVersions.Value; + public IReadOnlyList LegacyGameVersions => _legacyGameVersions.Value; /// /// TODO @@ -163,24 +153,33 @@ public GameVersionViewModel? SelectedGameVersion allInstalledGameVersions.Insert(0, installedStoreVersion); if (availableGameVersions is not null && allInstalledGameVersions.Count == 0) - return availableGameVersions.Select(static gameVersion => new GameVersionViewModel(gameVersion)).ToArray(); + return availableGameVersions.Select(gameVersion => new GameVersionViewModel(gameVersion, _installDirValidator)).ToArray(); if (availableGameVersions is null) - return allInstalledGameVersions.Select(static gameVersion => new GameVersionViewModel(gameVersion)).ToArray(); + return allInstalledGameVersions.Select(gameVersion => new GameVersionViewModel(gameVersion, _installDirValidator)).ToArray(); foreach (IGameVersion gameVersion in availableGameVersions) gameVersion.InstallDir = allInstalledGameVersions.FirstOrDefault(x => x.GameVersion == gameVersion.GameVersion)?.InstallDir; - return availableGameVersions.Select(static gameVersion => new GameVersionViewModel(gameVersion)).ToArray(); + return availableGameVersions.Select(gameVersion => new GameVersionViewModel(gameVersion, _installDirValidator)).ToArray(); } private async Task InstallSelectedLegacyGameVersionAsync() { GameVersionViewModel selectedGameVersion = SelectedGameVersion!; StatusProgress.Report(new ProgressInfo(StatusType.Installing, selectedGameVersion.GameVersion.GameVersion)); - string? installDir = await _legacyGameVersionInstaller.InstallLegacyGameVersionAsync(selectedGameVersion.GameVersion, CancellationToken.None, StatusProgress).ConfigureAwait(false); + using CancellationTokenSource cts = new(); + using IDisposable subscription = SteamAuthenticationViewModel.CancelCommand.Subscribe(_ => cts.Cancel()); + string? installDir = await _legacyGameVersionInstaller.InstallLegacyGameVersionAsync(selectedGameVersion.GameVersion, cts.Token, StatusProgress).ConfigureAwait(false); + if (installDir is null) + { + StatusProgress.Report(new ProgressInfo(StatusType.Failed, null)); + return false; + } + selectedGameVersion.InstallDir = installDir; - return installDir is not null; + StatusProgress.Report(new ProgressInfo(StatusType.Completed, null)); + return true; } private async Task UninstallSelectedLegacyGameVersionAsync() @@ -191,5 +190,20 @@ private async Task UninstallSelectedLegacyGameVersionAsync() selectedGameVersion.InstallDir = null; return success; } + + private void MarkStoreVersionAsInstalled(IGameVersion storeVersion, IEnumerable tabs) + { + foreach (LegacyGameVersionsTab tab in tabs) + { + GameVersionViewModel? storeInstalledVersion = tab.Versions.FirstOrDefault(version => version.GameVersion.GameVersion == storeVersion.GameVersion); + if (storeInstalledVersion is null) + continue; + + storeInstalledVersion.InstallDir = storeVersion.InstallDir; + storeInstalledVersion.GameVersion.InstallDir = storeVersion.InstallDir; + SelectedGameVersion = storeInstalledVersion; + break; + } + } } } diff --git a/BeatSaberModManager/ViewModels/SteamAuthenticationViewModel.cs b/BeatSaberModManager/ViewModels/SteamAuthenticationViewModel.cs index e8cd406..5ef132c 100644 --- a/BeatSaberModManager/ViewModels/SteamAuthenticationViewModel.cs +++ b/BeatSaberModManager/ViewModels/SteamAuthenticationViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Reactive; using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; using System.Threading; using System.Threading.Tasks; @@ -19,7 +20,8 @@ namespace BeatSaberModManager.ViewModels public sealed class SteamAuthenticationViewModel : ViewModelBase, ISteamAuthenticator, IDisposable { private readonly Steam3Session _session; - private readonly CancellationTokenSource _cancellationTokenSource = new(); + + private CancellationTokenSource? _cancellationTokenSource; /// /// @@ -29,21 +31,39 @@ public SteamAuthenticationViewModel(Steam3Session session) ArgumentNullException.ThrowIfNull(session); _session = session; IObservable canLogin = this.WhenAnyValue(static x => x.Username, static x => x.Password) - .Select(static x => !string.IsNullOrWhiteSpace(x.Item1) && string.IsNullOrWhiteSpace(x.Item2)); - LoginCommand = ReactiveCommand.CreateFromTask(LoginAsync, canLogin); - CancelCommand = ReactiveCommand.Create(_cancellationTokenSource.Cancel); + .Select(static x => !string.IsNullOrWhiteSpace(x.Item1) && !string.IsNullOrWhiteSpace(x.Item2)); + LoginCommand = ReactiveCommand.CreateFromTask(LoginWithCredentialsAsync, canLogin); + CancelCommand = ReactiveCommand.Create(() => _cancellationTokenSource?.Cancel()); + IObservable canSubmitSteamGuardCode = this.WhenAnyValue(static x => x.SteamGuardCode) + .Select(static code => code is not null && code.Length == 5); + SubmitSteamGuardCodeCommand = ReactiveCommand.Create(() => SteamGuardCode!, canSubmitSteamGuardCode); } + /// + /// TODO + /// + public Interaction AuthenticateSteamInteraction { get; } = new(RxApp.MainThreadScheduler); + + /// + /// + /// + public Interaction GetSteamGuardCodeInteraction { get; } = new(RxApp.MainThreadScheduler); + /// /// /// - public ReactiveCommand LoginCommand { get; } + public ReactiveCommand LoginCommand { get; } /// /// /// public ReactiveCommand CancelCommand { get; } + /// + /// + /// + public ReactiveCommand SubmitSteamGuardCodeCommand { get; } + /// /// /// @@ -88,39 +108,54 @@ public bool RememberPassword private bool _rememberPassword; + /// + /// + /// + public string? SteamGuardCode + { + get => _steamGuardCode; + set => this.RaiseAndSetIfChanged(ref _steamGuardCode, value); + } + + private string? _steamGuardCode; + /// - public Task GetDeviceCodeAsync(bool previousCodeWasIncorrect) => throw new System.NotImplementedException(); + public Task GetDeviceCodeAsync(bool previousCodeWasIncorrect) => GetSteamGuardCodeInteraction.Handle(previousCodeWasIncorrect).ToTask(); /// public Task GetEmailCodeAsync(string email, bool previousCodeWasIncorrect) => throw new System.NotImplementedException(); /// - public Task AcceptDeviceConfirmationAsync() => Task.FromResult(true); + public Task AcceptDeviceConfirmationAsync() => Task.FromResult(false); /// /// /// /// - public async Task AuthenticateAsync() + public Task AuthenticateAsync() => AuthenticateSteamInteraction.Handle(Unit.Default).ToTask(); + + /// + /// + /// + /// + public Task StartAuthenticationAsync() { - IObservable qrAuthSessionObservable = Observable.FromAsync(() => _session.SteamClient.Authentication.BeginAuthSessionViaQRAsync(new AuthSessionDetails { Authenticator = this })); - qrAuthSessionObservable.SelectMany(static x => Observable - .FromEvent(handler => x.ChallengeURLChanged += handler, handler => x.ChallengeURLChanged -= handler) - .Select(_ => x.ChallengeURL) - .StartWith(x.ChallengeURL)) - .Subscribe(challengeUrl => LoginChallenge = challengeUrl); - return await qrAuthSessionObservable.SelectMany(x => x.PollingWaitForResultAsync(_cancellationTokenSource.Token)) + _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = new CancellationTokenSource(); + + return Observable.StartAsync(LoginWithQrCodeAsync) .Merge(LoginCommand) - .FirstAsync(); + .FirstAsync() + .ToTask(); } /// public void Dispose() { - _cancellationTokenSource.Dispose(); + _cancellationTokenSource?.Dispose(); } - private async Task LoginAsync() + private async Task LoginWithCredentialsAsync() { AuthSessionDetails details = new() { @@ -131,7 +166,40 @@ private async Task LoginAsync() }; CredentialsAuthSession authSession = await _session.SteamClient.Authentication.BeginAuthSessionViaCredentialsAsync(details).ConfigureAwait(false); - return await authSession.PollingWaitForResultAsync(_cancellationTokenSource.Token).ConfigureAwait(false); + + try + { + AuthPollResult result = await authSession.PollingWaitForResultAsync(_cancellationTokenSource!.Token).ConfigureAwait(false); + await _cancellationTokenSource.CancelAsync().ConfigureAwait(false); + return result; + } + catch (TaskCanceledException) + { + return null; + } + } + + private async Task LoginWithQrCodeAsync() + { + AuthSessionDetails details = new() + { + Authenticator = this + }; + + QrAuthSession authSession = await _session.SteamClient.Authentication.BeginAuthSessionViaQRAsync(details).ConfigureAwait(false); + LoginChallenge = authSession.ChallengeURL; + authSession.ChallengeURLChanged += () => LoginChallenge = authSession.ChallengeURL; + + try + { + AuthPollResult result = await authSession.PollingWaitForResultAsync(_cancellationTokenSource!.Token).ConfigureAwait(false); + await _cancellationTokenSource.CancelAsync().ConfigureAwait(false); + return result; + } + catch (TaskCanceledException) + { + return null; + } } } } diff --git a/BeatSaberModManager/Views/Controls/CardControl.cs b/BeatSaberModManager/Views/Controls/CardControl.cs index 5b0241d..3c5e06b 100644 --- a/BeatSaberModManager/Views/Controls/CardControl.cs +++ b/BeatSaberModManager/Views/Controls/CardControl.cs @@ -1,6 +1,5 @@ using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Primitives; using Avalonia.Media; using Avalonia.Styling; diff --git a/BeatSaberModManager/Views/Dialogs/SteamGuardCodeView.axaml b/BeatSaberModManager/Views/Dialogs/SteamGuardCodeView.axaml new file mode 100644 index 0000000..8428e09 --- /dev/null +++ b/BeatSaberModManager/Views/Dialogs/SteamGuardCodeView.axaml @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/BeatSaberModManager/Views/Dialogs/SteamGuardCodeView.axaml.cs b/BeatSaberModManager/Views/Dialogs/SteamGuardCodeView.axaml.cs new file mode 100644 index 0000000..055a59b --- /dev/null +++ b/BeatSaberModManager/Views/Dialogs/SteamGuardCodeView.axaml.cs @@ -0,0 +1,19 @@ +using Avalonia.Controls; + + +namespace BeatSaberModManager.Views.Dialogs +{ + /// + /// TODO + /// + public partial class SteamGuardCodeView : UserControl + { + /// + /// + /// + public SteamGuardCodeView() + { + InitializeComponent(); + } + } +} diff --git a/BeatSaberModManager/Views/Dialogs/SteamLoginView.axaml b/BeatSaberModManager/Views/Dialogs/SteamLoginView.axaml new file mode 100644 index 0000000..405a46f --- /dev/null +++ b/BeatSaberModManager/Views/Dialogs/SteamLoginView.axaml @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/BeatSaberModManager/Views/Dialogs/SteamLoginView.axaml.cs b/BeatSaberModManager/Views/Dialogs/SteamLoginView.axaml.cs new file mode 100644 index 0000000..c843a0a --- /dev/null +++ b/BeatSaberModManager/Views/Dialogs/SteamLoginView.axaml.cs @@ -0,0 +1,19 @@ +using Avalonia.Controls; + + +namespace BeatSaberModManager.Views.Dialogs +{ + /// + /// TODO + /// + public partial class SteamLoginView : UserControl + { + /// + /// + /// + public SteamLoginView() + { + InitializeComponent(); + } + } +} diff --git a/BeatSaberModManager/Views/Pages/LegacyGameVersionsPage.axaml b/BeatSaberModManager/Views/Pages/LegacyGameVersionsPage.axaml index b18f1b7..ed4cfb0 100644 --- a/BeatSaberModManager/Views/Pages/LegacyGameVersionsPage.axaml +++ b/BeatSaberModManager/Views/Pages/LegacyGameVersionsPage.axaml @@ -2,51 +2,22 @@ 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:sys="using:System" - xmlns:linq="using:System.Linq" xmlns:vm="using:BeatSaberModManager.ViewModels" xmlns:c="using:BeatSaberModManager.Views.Controls" xmlns:asyncImageLoader="using:AsyncImageLoader" - xmlns:labs="using:Avalonia.Labs.Controls" - xmlns:qr="clr-namespace:Avalonia.Labs.Qr;assembly=Avalonia.Labs.Qr" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="BeatSaberModManager.Views.Pages.LegacyGameVersionsPage" - x:DataType="vm:LegacyGameVersionsViewModel" - x:Name="LegacyGameVersionsPageControl"> - - - - - - - - - - - + x:DataType="vm:LegacyGameVersionsViewModel"> - + - + - @@ -59,10 +30,10 @@ - + - +