From 9ecb32c3d233be5aa74b858292f96e45055924cd Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Fri, 22 Jul 2022 18:25:47 -0600 Subject: [PATCH] Added login dialogs --- .../AvaloniaUI/AvaloniaUtils.cs | 11 ++ .../DirectoryOrCustomSelectControl.axaml.cs | 6 +- .../LibationWinForms/AvaloniaUI/MessageBox.cs | 92 ++++-------- .../ViewModels/ProcessBookViewModel.cs | 2 +- .../ViewModels/ProductsDisplayViewModel.cs | 4 +- .../Views/Dialogs/AccountsDialog.axaml.cs | 38 ++--- .../Views/Dialogs/BookDetailsDialog.axaml | 21 ++- .../Views/Dialogs/BookDetailsDialog.axaml.cs | 9 +- .../Views/Dialogs/EditTemplateDialog.axaml | 7 +- .../Views/Dialogs/EditTemplateDialog.axaml.cs | 19 +-- .../Views/Dialogs/ImageDisplayDialog.axaml.cs | 2 +- .../Dialogs/LibationFilesDialog.axaml.cs | 2 +- .../Dialogs/Login/ApprovalNeededDialog.axaml | 33 ++++ .../Login/ApprovalNeededDialog.axaml.cs | 30 ++++ .../Views/Dialogs/Login/AvaloniaLoginBase.cs | 22 +++ .../Dialogs/Login/AvaloniaLoginCallback.cs | 55 +++++++ .../Dialogs/Login/AvaloniaLoginChoiceEager.cs | 47 ++++++ .../Views/Dialogs/Login/CaptchaDialog.axaml | 54 +++++++ .../Dialogs/Login/CaptchaDialog.axaml.cs | 40 +++++ .../Dialogs/Login/LoginCallbackDialog.axaml | 38 +++++ .../Login/LoginCallbackDialog.axaml.cs | 50 ++++++ .../Login/LoginChoiceEagerDialog.axaml | 66 ++++++++ .../Login/LoginChoiceEagerDialog.axaml.cs | 45 ++++++ .../Dialogs/Login/LoginExternalDialog.axaml | 111 ++++++++++++++ .../Login/LoginExternalDialog.axaml.cs | 71 +++++++++ .../Views/Dialogs/Login/MfaDialog.axaml | 18 +++ .../Views/Dialogs/Login/MfaDialog.axaml.cs | 142 ++++++++++++++++++ .../Views/Dialogs/Login/_2faCodeDialog.axaml | 32 ++++ .../Dialogs/Login/_2faCodeDialog.axaml.cs | 33 ++++ .../MessageBoxAlertAdminDialog.axaml.cs | 6 +- .../Views/Dialogs/SettingsDialog.axaml.cs | 128 ++++++++++------ .../MainWindow/MainWindow.Export.axaml.cs | 6 +- .../MainWindow/MainWindow.Filter.axaml.cs | 2 +- .../MainWindow/MainWindow.Liberate.axaml.cs | 2 +- .../MainWindow.ProcessQueue.axaml.cs | 4 +- .../MainWindow/MainWindow.ScanAuto.axaml.cs | 2 +- .../MainWindow/MainWindow.ScanManual.axaml.cs | 8 +- .../MainWindow/MainWindow.Settings.axaml.cs | 2 +- .../MainWindow.VisibleBooks.axaml.cs | 6 +- .../Views/MainWindow/MainWindow.axaml.cs | 3 +- 40 files changed, 1100 insertions(+), 169 deletions(-) create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/ApprovalNeededDialog.axaml create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/ApprovalNeededDialog.axaml.cs create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/AvaloniaLoginBase.cs create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/AvaloniaLoginCallback.cs create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/AvaloniaLoginChoiceEager.cs create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/CaptchaDialog.axaml create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/CaptchaDialog.axaml.cs create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/LoginCallbackDialog.axaml create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/LoginCallbackDialog.axaml.cs create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/LoginChoiceEagerDialog.axaml create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/LoginChoiceEagerDialog.axaml.cs create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/LoginExternalDialog.axaml create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/LoginExternalDialog.axaml.cs create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/MfaDialog.axaml create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/MfaDialog.axaml.cs create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/_2faCodeDialog.axaml create mode 100644 Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/_2faCodeDialog.axaml.cs diff --git a/Source/LibationWinForms/AvaloniaUI/AvaloniaUtils.cs b/Source/LibationWinForms/AvaloniaUI/AvaloniaUtils.cs index 30ef7dd2..200d8cf5 100644 --- a/Source/LibationWinForms/AvaloniaUI/AvaloniaUtils.cs +++ b/Source/LibationWinForms/AvaloniaUI/AvaloniaUtils.cs @@ -1,5 +1,7 @@ using Avalonia.Media; using System; +using System.Threading; +using System.Threading.Tasks; namespace LibationWinForms.AvaloniaUI { @@ -13,5 +15,14 @@ namespace LibationWinForms.AvaloniaUI return brush; return defaultBrush; } + + public static T ShowDialogSynchronously(this Avalonia.Controls.Window window, Avalonia.Controls.Window owner) + { + using var source = new CancellationTokenSource(); + var dialogTask = window.ShowDialog(owner); + dialogTask.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext()); + Avalonia.Threading.Dispatcher.UIThread.MainLoop(source.Token); + return dialogTask.Result; + } } } diff --git a/Source/LibationWinForms/AvaloniaUI/Controls/DirectoryOrCustomSelectControl.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Controls/DirectoryOrCustomSelectControl.axaml.cs index 0ee5b046..b215fc40 100644 --- a/Source/LibationWinForms/AvaloniaUI/Controls/DirectoryOrCustomSelectControl.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Controls/DirectoryOrCustomSelectControl.axaml.cs @@ -116,10 +116,12 @@ namespace LibationWinForms.AvaloniaUI.Controls private void setDirectory() { - Directory - = customStates.CustomChecked ? customStates.CustomDir + var path1 + = customStates.CustomChecked ? customStates.CustomDir : directorySelectControl.SelectedDirectory is Configuration.KnownDirectories.AppDir ? Configuration.AppDir_Absolute : Configuration.GetKnownDirectoryPath(directorySelectControl.SelectedDirectory); + Directory + = System.IO.Path.Combine(path1 ?? string.Empty, SubDirectory); } diff --git a/Source/LibationWinForms/AvaloniaUI/MessageBox.cs b/Source/LibationWinForms/AvaloniaUI/MessageBox.cs index 838f06fd..0a974636 100644 --- a/Source/LibationWinForms/AvaloniaUI/MessageBox.cs +++ b/Source/LibationWinForms/AvaloniaUI/MessageBox.cs @@ -26,7 +26,6 @@ namespace LibationWinForms.AvaloniaUI Continue = 11 } - public enum MessageBoxIcon { None = 0, @@ -39,6 +38,7 @@ namespace LibationWinForms.AvaloniaUI Asterisk = 64, Information = 64 } + public enum MessageBoxButtons { OK, @@ -74,10 +74,8 @@ namespace LibationWinForms.AvaloniaUI /// -or- /// is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. - public static async Task Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) - { - return await ShowCore(null, text, caption, buttons, icon, defaultButton); - } + public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) + => ShowCoreAsync(null, text, caption, buttons, icon, defaultButton); /// Displays a message box with specified text, caption, buttons, and icon. @@ -90,10 +88,8 @@ namespace LibationWinForms.AvaloniaUI /// -or- /// The parameter specified is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. - public static async Task Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) - { - return await ShowCore(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); - } + public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) + => ShowCoreAsync(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); /// Displays a message box with specified text, caption, and buttons. @@ -103,28 +99,22 @@ namespace LibationWinForms.AvaloniaUI /// One of the values. /// The parameter specified is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. - public static async Task Show(string text, string caption, MessageBoxButtons buttons) - { - return await ShowCore(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - } + public static DialogResult Show(string text, string caption, MessageBoxButtons buttons) + => ShowCoreAsync(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); /// Displays a message box with specified text and caption. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values. - public static async Task Show(string text, string caption) - { - return await ShowCore(null, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - } + public static DialogResult Show(string text, string caption) + => ShowCoreAsync(null, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); /// Displays a message box with specified text. /// The text to display in the message box. /// One of the values. - public static async Task Show(string text) - { - return await ShowCore(null, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - } + public static DialogResult Show(string text) + => ShowCoreAsync(null, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); /// Displays a message box in front of the specified object and with the specified text, caption, buttons, icon, default button, and options. @@ -146,10 +136,9 @@ namespace LibationWinForms.AvaloniaUI /// /// -or- /// specified an invalid combination of . - public static async Task Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) - { - return await ShowCore(owner, text, caption, buttons, icon, defaultButton); - } + public static DialogResult Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) + => ShowCoreAsync(owner, text, caption, buttons, icon, defaultButton); + /// Displays a message box in front of the specified object and with the specified text, caption, buttons, and icon. @@ -164,10 +153,8 @@ namespace LibationWinForms.AvaloniaUI /// -or- /// is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. - public static async Task Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) - { - return await ShowCore(owner, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); - } + public static DialogResult Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) + => ShowCoreAsync(owner, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); /// Displays a message box in front of the specified object and with the specified text, caption, and buttons. /// An implementation of that will own the modal dialog box. @@ -178,35 +165,29 @@ namespace LibationWinForms.AvaloniaUI /// /// is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. - public static async Task Show(Window owner, string text, string caption, MessageBoxButtons buttons) - { - return await ShowCore(owner, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - } + public static DialogResult Show(Window owner, string text, string caption, MessageBoxButtons buttons) + => ShowCoreAsync(owner, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); /// Displays a message box in front of the specified object and with the specified text and caption. /// An implementation of that will own the modal dialog box. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values. - public static async Task Show(Window owner, string text, string caption) - { - return await ShowCore(owner, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - } - + public static DialogResult Show(Window owner, string text, string caption) + => ShowCoreAsync(owner, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); /// Displays a message box in front of the specified object and with the specified text. /// An implementation of that will own the modal dialog box. /// The text to display in the message box. /// One of the values. - public static async Task Show(Window owner, string text) - { - return await ShowCore(owner, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - } + public static DialogResult Show(Window owner, string text) + => ShowCoreAsync(owner, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); + public static async Task VerboseLoggingWarning_ShowIfTrue() { // when turning on debug (and especially Verbose) to share logs, some privacy settings may not be obscured if (Serilog.Log.Logger.IsVerboseEnabled()) - await Show(@" + Show(@" Warning: verbose logging is enabled. This should be used for debugging only. It creates many @@ -219,7 +200,7 @@ Libation. ".Trim(), "Verbose logging enabled", MessageBoxButtons.OK, MessageBoxIcon.Warning); } - public static async Task ShowConfirmationDialog(Window owner, IEnumerable libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) + public static DialogResult ShowConfirmationDialog(Window owner, IEnumerable libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) { if (libraryBooks is null || !libraryBooks.Any()) return DialogResult.Cancel; @@ -234,7 +215,7 @@ Libation. = string.Format(format, $"{thisThese} {count} {bookBooks}") + $"\r\n\r\n{titlesAgg}"; - return await ShowCore(owner, + return ShowCoreAsync(owner, message, title, MessageBoxButtons.YesNo, @@ -263,18 +244,11 @@ Libation. var form = new MessageBoxAlertAdminDialog(text, caption, exception); - await DisplayWindow(form, owner); + DisplayWindow(form, owner); } - private static async Task ShowCore(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) - { - if (Avalonia.Threading.Dispatcher.UIThread.CheckAccess()) - return await ShowCore2(owner, message, caption, buttons, icon, defaultButton); - else - return await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => ShowCore2(owner, message, caption, buttons, icon, defaultButton)); - } - private static async Task ShowCore2(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) + private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) { var dialog = new MessageBoxWindow(); @@ -307,15 +281,15 @@ Libation. dialog.Height = dialog.MinHeight; dialog.Width = dialog.MinWidth; - return await DisplayWindow(dialog, owner); + return DisplayWindow(dialog, owner); } - private static async Task DisplayWindow(Window toDisplay, Window owner) + private static DialogResult DisplayWindow(Window toDisplay, Window owner) { if (owner is null) { if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - return await toDisplay.ShowDialog(desktop.MainWindow); + return toDisplay.ShowDialogSynchronously(desktop.MainWindow); } else { @@ -329,7 +303,7 @@ Libation. }; window.Show(); - var result = await toDisplay.ShowDialog(window); + var result = toDisplay.ShowDialogSynchronously(window); window.Close(); return result; } @@ -337,7 +311,7 @@ Libation. } else { - return await toDisplay.ShowDialog(owner); + return toDisplay.ShowDialogSynchronously(owner); } } diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessBookViewModel.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessBookViewModel.cs index 2e785533..f9b7d997 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessBookViewModel.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessBookViewModel.cs @@ -346,7 +346,7 @@ $@" Title: {libraryBook.Book.Title} } // if null then ask user - dialogResult ??= await MessageBox.Show(string.Format(SkipDialogText + "\r\n\r\nSee Settings to avoid this box in the future.", details), "Skip importing this book?", SkipDialogButtons, MessageBoxIcon.Question, SkipDialogDefaultButton); + dialogResult ??= MessageBox.Show(string.Format(SkipDialogText + "\r\n\r\nSee Settings to avoid this box in the future.", details), "Skip importing this book?", SkipDialogButtons, MessageBoxIcon.Question, SkipDialogDefaultButton); if (dialogResult == DialogResult.Abort) return ProcessBookResult.FailedAbort; diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProductsDisplayViewModel.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProductsDisplayViewModel.cs index c5f884af..6097a722 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProductsDisplayViewModel.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProductsDisplayViewModel.cs @@ -243,7 +243,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels return; var libraryBooks = selectedBooks.Select(rge => rge.LibraryBook).ToList(); - var result = await MessageBox.ShowConfirmationDialog( + var result = MessageBox.ShowConfirmationDialog( null, libraryBooks, $"Are you sure you want to remove {selectedBooks.Count} books from Libation's library?", @@ -307,7 +307,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels .Select(lbe => lbe.LibraryBook) .Where(lb => !lb.Book.HasLiberated()); - var removedBooks = await LibraryCommands.FindInactiveBooks(Login.WinformLoginChoiceEager.ApiExtendedFunc, lib, accounts); + var removedBooks = await LibraryCommands.FindInactiveBooks(Views.Dialogs.Login.AvaloniaLoginChoiceEager.ApiExtendedFunc, lib, accounts); var removable = allBooks.Where(lbe => removedBooks.Any(rb => rb.Book.AudibleProductId == lbe.AudibleProductId)).ToList(); diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/AccountsDialog.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/AccountsDialog.axaml.cs index f95e028c..0a11da76 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/AccountsDialog.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/AccountsDialog.axaml.cs @@ -56,13 +56,17 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs // only persist in 'save' step using var persister = AudibleApiStorage.GetAccountsSettingsPersister(); var accounts = persister.AccountsSettings.Accounts; - if (!accounts.Any()) - return; + if (accounts.Any()) + { + foreach (var account in accounts) + AddAccountToGrid(account); + } DataContext = this; - - foreach (var account in accounts) - AddAccountToGrid(account); + addBlankAccount(); + } + private void addBlankAccount() + { var newBlank = new AccountDto(); newBlank.PropertyChanged += AccountDto_PropertyChanged; @@ -89,9 +93,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs if (Accounts.Any(a => a.IsDefault)) return; - var newBlank = new AccountDto(); - newBlank.PropertyChanged += AccountDto_PropertyChanged; - Accounts.Insert(Accounts.Count, newBlank); + addBlankAccount(); } public void DeleteButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e) @@ -134,7 +136,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs if (persister.AccountsSettings.Accounts.Any(a => a.AccountId == account.AccountId && a.IdentityTokens.Locale.Name == account.Locale.Name)) { - await MessageBox.Show(this, $"An account with that account id and country already exists.\r\n\r\nAccount ID: {account.AccountId}\r\nCountry: {account.Locale.Name}", "Cannot Add Duplicate Account"); + MessageBox.Show(this, $"An account with that account id and country already exists.\r\n\r\nAccount ID: {account.AccountId}\r\nCountry: {account.Locale.Name}", "Cannot Add Duplicate Account"); return; } @@ -144,7 +146,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs } catch (Exception ex) { - await MessageBox.ShowAdminAlert( + MessageBox.ShowAdminAlert( this, $"An error occurred while importing an account from:\r\n{filePath[0]}\r\n\r\nIs the file encrypted?", "Error Importing Account", @@ -163,7 +165,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs try { - if (!await inputIsValid()) + if (!inputIsValid()) return; // without transaction, accounts persister will write ANY EDIT immediately to file @@ -190,8 +192,6 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs AvaloniaXamlLoader.Load(this); } - - private void persist(AccountsSettings accountsSettings) { var existingAccounts = accountsSettings.Accounts; @@ -222,7 +222,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs : dto.AccountName.Trim(); } } - private async Task inputIsValid() + private bool inputIsValid() { foreach (var dto in Accounts.ToList()) { @@ -234,13 +234,13 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs if (string.IsNullOrWhiteSpace(dto.AccountId)) { - await MessageBox.Show(this, "Account id cannot be blank. Please enter an account id for all accounts.", "Blank account", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(this, "Account id cannot be blank. Please enter an account id for all accounts.", "Blank account", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if (string.IsNullOrWhiteSpace(dto.SelectedLocale?.Name)) { - await MessageBox.Show(this, "Please select a locale (i.e.: country or region) for all accounts.", "Blank region", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(this, "Please select a locale (i.e.: country or region) for all accounts.", "Blank region", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } } @@ -260,7 +260,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs if (account.IdentityTokens?.IsValid != true) { - await MessageBox.Show(this, "This account hasn't been authenticated yet. First scan your library to log into your account, then try exporting again.", "Account Not Authenticated"); + MessageBox.Show(this, "This account hasn't been authenticated yet. First scan your library to log into your account, then try exporting again.", "Account Not Authenticated"); return; } @@ -283,11 +283,11 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs File.WriteAllText(fileName, jsonText); - await MessageBox.Show(this, $"Successfully exported {account.AccountName} to\r\n\r\n{fileName}", "Success!"); + MessageBox.Show(this, $"Successfully exported {account.AccountName} to\r\n\r\n{fileName}", "Success!"); } catch (Exception ex) { - await MessageBox.ShowAdminAlert( + MessageBox.ShowAdminAlert( this, $"An error occurred while exporting account:\r\n{account.AccountName}", "Error Exporting Account", diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/BookDetailsDialog.axaml b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/BookDetailsDialog.axaml index 5ba6c079..488a0e22 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/BookDetailsDialog.axaml +++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/BookDetailsDialog.axaml @@ -17,13 +17,30 @@ - + + + + + + + + + diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/BookDetailsDialog.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/BookDetailsDialog.axaml.cs index d884667f..87f15729 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/BookDetailsDialog.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/BookDetailsDialog.axaml.cs @@ -4,6 +4,7 @@ using Avalonia.Controls; using Avalonia.Markup.Xaml; using Avalonia.Media.Imaging; using DataLayer; +using Dinah.Core; using LibationFileManager; using LibationWinForms.AvaloniaUI.ViewModels; using System.Collections.Generic; @@ -34,6 +35,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs public BookDetailsDialog() { InitializeComponent(); + ControlToFocusOnShow = this.Find(nameof(tagsTbox)); if (Design.IsDesignMode) { @@ -46,13 +48,18 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs LibraryBook = libraryBook; } - protected override void SaveAndClose() { SaveButton_Clicked(null, null); base.SaveAndClose(); } + public void GoToAudible_Tapped(object sender, Avalonia.Interactivity.RoutedEventArgs e) + { + var locale = AudibleApi.Localization.Get(_libraryBook.Book.Locale); + var link = $"https://www.audible.{locale.TopDomain}/pd/{_libraryBook.Book.AudibleProductId}"; + Go.To.Url(link); + } public void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e) { diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/EditTemplateDialog.axaml b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/EditTemplateDialog.axaml index 41601452..ff061c33 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/EditTemplateDialog.axaml +++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/EditTemplateDialog.axaml @@ -38,7 +38,7 @@ Content="Reset to Default" Click="ResetButton_Click" /> - + - + + RowDefinitions="Auto,*,80" HorizontalAlignment="Stretch"> workingTemplateText = value; - public async Task Validate() + public bool Validate() { if (template.IsValid(workingTemplateText)) return true; @@ -127,7 +126,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs .GetErrors(workingTemplateText) .Select(err => $"- {err}") .Aggregate((a, b) => $"{a}\r\n{b}"); - await MessageBox.Show($"This template text is not valid. Errors:\r\n{errors}", "Invalid", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show($"This template text is not valid. Errors:\r\n{errors}", "Invalid", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } @@ -232,11 +231,13 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs for(int i = 0; i < wordsSplit.Length; i++) { - var tb = new TextBlock(); - tb.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Bottom; - - tb.Text = wordsSplit[i] + (i == wordsSplit.Length - 1 ? "" : " "); - tb.FontWeight = item.Item2; + var tb = new TextBlock + { + VerticalAlignment = Avalonia.Layout.VerticalAlignment.Bottom, + TextWrapping = TextWrapping.Wrap, + Text = wordsSplit[i] + (i == wordsSplit.Length - 1 ? "" : " "), + FontWeight = item.Item2 + }; WrapPanel.Children.Add(tb); } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml.cs index 41c62b39..7df5fe48 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml.cs @@ -64,7 +64,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs catch (Exception ex) { Serilog.Log.Logger.Error(ex, $"Failed to save picture to {fileName}"); - await MessageBox.Show(this, $"An error was encountered while trying to save the picture\r\n\r\n{ex.Message}", "Failed to save picture", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + MessageBox.Show(this, $"An error was encountered while trying to save the picture\r\n\r\n{ex.Message}", "Failed to save picture", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); } } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/LibationFilesDialog.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/LibationFilesDialog.axaml.cs index d728309f..d91e3326 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/LibationFilesDialog.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/LibationFilesDialog.axaml.cs @@ -35,7 +35,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs if (!System.IO.Directory.Exists(libationDir)) { - await MessageBox.Show("Not saving change to Libation Files location. This folder does not exist:\r\n" + libationDir, "Folder does not exist", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Not saving change to Libation Files location. This folder does not exist:\r\n" + libationDir, "Folder does not exist", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/ApprovalNeededDialog.axaml b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/ApprovalNeededDialog.axaml new file mode 100644 index 00000000..b4c7ff29 --- /dev/null +++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/Login/ApprovalNeededDialog.axaml @@ -0,0 +1,33 @@ + + + + + + + + +