Libation Runs on MacOS

This commit is contained in:
Michael Bucari-Tovo 2022-07-30 16:09:31 -06:00
parent 8020ded642
commit 0bfa609058
30 changed files with 147 additions and 171 deletions

View File

@ -5,10 +5,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AudibleApi" Version="4.5.0.1" /> <ProjectReference Include="..\..\..\audible api\AudibleApi\AudibleApi\AudibleApi.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LibationFileManager\LibationFileManager.csproj" /> <ProjectReference Include="..\LibationFileManager\LibationFileManager.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -115,7 +115,7 @@ namespace LibationAvalonia
base.OnFrameworkInitializationCompleted(); base.OnFrameworkInitializationCompleted();
} }
private void Setup_Closing(object sender, System.ComponentModel.CancelEventArgs e) private async void Setup_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{ {
var setupDialog = sender as SetupDialog; var setupDialog = sender as SetupDialog;
var desktop = ApplicationLifetime as IClassicDesktopStyleApplicationLifetime; var desktop = ApplicationLifetime as IClassicDesktopStyleApplicationLifetime;
@ -128,9 +128,9 @@ namespace LibationAvalonia
if ((!setupDialog.IsNewUser if ((!setupDialog.IsNewUser
&& !setupDialog.IsReturningUser) || && !setupDialog.IsReturningUser) ||
!RunInstall(setupDialog)) !await RunInstall(setupDialog))
{ {
CancelInstallation(); await CancelInstallation();
return; return;
} }
@ -138,7 +138,7 @@ namespace LibationAvalonia
// most migrations go in here // most migrations go in here
AppScaffolding.LibationScaffolding.RunPostConfigMigrations(setupDialog.Config); AppScaffolding.LibationScaffolding.RunPostConfigMigrations(setupDialog.Config);
MessageBox.VerboseLoggingWarning_ShowIfTrue(); await MessageBox.VerboseLoggingWarning_ShowIfTrue();
#if !DEBUG #if !DEBUG
//AutoUpdater.NET only works for WinForms or WPF application projects. //AutoUpdater.NET only works for WinForms or WPF application projects.
@ -154,11 +154,11 @@ namespace LibationAvalonia
var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file."; var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file.";
try try
{ {
MessageBox.ShowAdminAlert(null, body, title, ex); await MessageBox.ShowAdminAlert(null, body, title, ex);
} }
catch catch
{ {
MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error); await MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error);
} }
return; return;
} }
@ -168,7 +168,7 @@ namespace LibationAvalonia
ShowMainWindow(desktop); ShowMainWindow(desktop);
} }
private static bool RunInstall(SetupDialog setupDialog) private static async Task<bool> RunInstall(SetupDialog setupDialog)
{ {
var config = setupDialog.Config; var config = setupDialog.Config;
@ -181,7 +181,7 @@ namespace LibationAvalonia
var libationFilesDialog = new LibationFilesDialog(); var libationFilesDialog = new LibationFilesDialog();
if (libationFilesDialog.ShowDialogSynchronously<DialogResult>(setupDialog) != DialogResult.OK) if (await libationFilesDialog.ShowDialog<DialogResult>(setupDialog) != DialogResult.OK)
return false; return false;
config.SetLibationFiles(libationFilesDialog.SelectedDirectory); config.SetLibationFiles(libationFilesDialog.SelectedDirectory);
@ -189,7 +189,7 @@ namespace LibationAvalonia
return true; return true;
// path did not result in valid settings // path did not result in valid settings
var continueResult = MessageBox.Show( var continueResult = await MessageBox.Show(
$"No valid settings were found at this location.\r\nWould you like to create a new install settings in this folder?\r\n\r\n{libationFilesDialog.SelectedDirectory}", $"No valid settings were found at this location.\r\nWould you like to create a new install settings in this folder?\r\n\r\n{libationFilesDialog.SelectedDirectory}",
"New install?", "New install?",
MessageBoxButtons.YesNo, MessageBoxButtons.YesNo,
@ -204,13 +204,13 @@ namespace LibationAvalonia
config.Books ??= Path.Combine(Configuration.UserProfile, "Books"); config.Books ??= Path.Combine(Configuration.UserProfile, "Books");
AppScaffolding.LibationScaffolding.PopulateMissingConfigValues(config); AppScaffolding.LibationScaffolding.PopulateMissingConfigValues(config);
return new SettingsDialog().ShowDialogSynchronously<DialogResult>(setupDialog) == DialogResult.OK return await new SettingsDialog().ShowDialog<DialogResult>(setupDialog) == DialogResult.OK
&& config.LibationSettingsAreValid; && config.LibationSettingsAreValid;
} }
static void CancelInstallation() static async Task CancelInstallation()
{ {
MessageBox.Show("Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning); await MessageBox.Show("Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
Environment.Exit(0); Environment.Exit(0);
} }

View File

@ -6,25 +6,5 @@ namespace Avalonia.Threading
{ {
internal static class AvaloniaThreadUtils internal static class AvaloniaThreadUtils
{ {
public static TResult Invoke<TResult>(this Dispatcher dispatcher, Func<TResult> function, DispatcherPriority dispatcherPriority = DispatcherPriority.Normal)
=> WaitOnDispatcherAndGetResult(dispatcher.InvokeAsync(function, dispatcherPriority), dispatcher);
public static void Invoke(this Dispatcher dispatcher, Action action, DispatcherPriority dispatcherPriority = DispatcherPriority.Normal)
=> WaitOnDispatcher(dispatcher.InvokeAsync(action, dispatcherPriority), dispatcher);
public static TResult WaitOnDispatcherAndGetResult<TResult>(this Task<TResult> task, Dispatcher dispatcher)
{
using var source = new CancellationTokenSource();
task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext());
dispatcher.MainLoop(source.Token);
return task.Result;
}
public static void WaitOnDispatcher(this Task task, Dispatcher dispatcher)
{
using var source = new CancellationTokenSource();
task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext());
dispatcher.MainLoop(source.Token);
}
} }
} }

View File

@ -17,9 +17,5 @@ namespace LibationAvalonia
return defaultBrush; return defaultBrush;
} }
public static T ShowDialogSynchronously<T>(this Avalonia.Controls.Window window, Avalonia.Controls.Window owner)
{
return window.ShowDialog<T>(owner).WaitOnDispatcherAndGetResult(Dispatcher.UIThread);
}
} }
} }

View File

@ -136,7 +136,7 @@ namespace LibationAvalonia.Dialogs
if (persister.AccountsSettings.Accounts.Any(a => a.AccountId == account.AccountId && a.IdentityTokens.Locale.Name == account.Locale.Name)) if (persister.AccountsSettings.Accounts.Any(a => a.AccountId == account.AccountId && a.IdentityTokens.Locale.Name == account.Locale.Name))
{ {
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"); 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");
return; return;
} }
@ -146,7 +146,7 @@ namespace LibationAvalonia.Dialogs
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.ShowAdminAlert( await MessageBox.ShowAdminAlert(
this, this,
$"An error occurred while importing an account from:\r\n{filePath[0]}\r\n\r\nIs the file encrypted?", $"An error occurred while importing an account from:\r\n{filePath[0]}\r\n\r\nIs the file encrypted?",
"Error Importing Account", "Error Importing Account",
@ -160,11 +160,11 @@ namespace LibationAvalonia.Dialogs
Export(acc); Export(acc);
} }
protected override void SaveAndClose() protected override async Task SaveAndCloseAsync()
{ {
try try
{ {
if (!inputIsValid()) if (!await inputIsValid())
return; return;
// without transaction, accounts persister will write ANY EDIT immediately to file // without transaction, accounts persister will write ANY EDIT immediately to file
@ -178,7 +178,7 @@ namespace LibationAvalonia.Dialogs
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.ShowAdminAlert(this, "Error attempting to save accounts", "Error saving accounts", ex); await MessageBox.ShowAdminAlert(this, "Error attempting to save accounts", "Error saving accounts", ex);
} }
} }
@ -221,7 +221,7 @@ namespace LibationAvalonia.Dialogs
: dto.AccountName.Trim(); : dto.AccountName.Trim();
} }
} }
private bool inputIsValid() private async Task<bool> inputIsValid()
{ {
foreach (var dto in Accounts.ToList()) foreach (var dto in Accounts.ToList())
{ {
@ -233,13 +233,13 @@ namespace LibationAvalonia.Dialogs
if (string.IsNullOrWhiteSpace(dto.AccountId)) if (string.IsNullOrWhiteSpace(dto.AccountId))
{ {
MessageBox.Show(this, "Account id cannot be blank. Please enter an account id for all accounts.", "Blank account", MessageBoxButtons.OK, MessageBoxIcon.Error); await MessageBox.Show(this, "Account id cannot be blank. Please enter an account id for all accounts.", "Blank account", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false; return false;
} }
if (string.IsNullOrWhiteSpace(dto.SelectedLocale?.Name)) if (string.IsNullOrWhiteSpace(dto.SelectedLocale?.Name))
{ {
MessageBox.Show(this, "Please select a locale (i.e.: country or region) for all accounts.", "Blank region", MessageBoxButtons.OK, MessageBoxIcon.Error); await MessageBox.Show(this, "Please select a locale (i.e.: country or region) for all accounts.", "Blank region", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false; return false;
} }
} }
@ -259,7 +259,7 @@ namespace LibationAvalonia.Dialogs
if (account.IdentityTokens?.IsValid != true) if (account.IdentityTokens?.IsValid != true)
{ {
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"); 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");
return; return;
} }
@ -282,11 +282,11 @@ namespace LibationAvalonia.Dialogs
File.WriteAllText(fileName, jsonText); File.WriteAllText(fileName, jsonText);
MessageBox.Show(this, $"Successfully exported {account.AccountName} to\r\n\r\n{fileName}", "Success!"); await MessageBox.Show(this, $"Successfully exported {account.AccountName} to\r\n\r\n{fileName}", "Success!");
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.ShowAdminAlert( await MessageBox.ShowAdminAlert(
this, this,
$"An error occurred while exporting account:\r\n{account.AccountName}", $"An error occurred while exporting account:\r\n{account.AccountName}",
"Error Exporting Account", "Error Exporting Account",

View File

@ -64,7 +64,7 @@ namespace LibationAvalonia.Dialogs
} }
protected override async Task SaveAndCloseAsync() protected override async Task SaveAndCloseAsync()
{ {
if (!_viewModel.Validate()) if (!await _viewModel.Validate())
return; return;
TemplateText = _viewModel.workingTemplateText; TemplateText = _viewModel.workingTemplateText;
@ -115,7 +115,7 @@ namespace LibationAvalonia.Dialogs
public void resetTextBox(string value) => workingTemplateText = value; public void resetTextBox(string value) => workingTemplateText = value;
public bool Validate() public async Task<bool> Validate()
{ {
if (template.IsValid(workingTemplateText)) if (template.IsValid(workingTemplateText))
return true; return true;
@ -123,7 +123,7 @@ namespace LibationAvalonia.Dialogs
.GetErrors(workingTemplateText) .GetErrors(workingTemplateText)
.Select(err => $"- {err}") .Select(err => $"- {err}")
.Aggregate((a, b) => $"{a}\r\n{b}"); .Aggregate((a, b) => $"{a}\r\n{b}");
MessageBox.Show($"This template text is not valid. Errors:\r\n{errors}", "Invalid", MessageBoxButtons.OK, MessageBoxIcon.Error); await MessageBox.Show($"This template text is not valid. Errors:\r\n{errors}", "Invalid", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false; return false;
} }

View File

@ -67,7 +67,7 @@ namespace LibationAvalonia.Dialogs
catch (Exception ex) catch (Exception ex)
{ {
Serilog.Log.Logger.Error(ex, $"Failed to save picture to {fileName}"); Serilog.Log.Logger.Error(ex, $"Failed to save picture to {fileName}");
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); 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);
} }
} }

View File

@ -33,14 +33,14 @@ namespace LibationAvalonia.Dialogs
DataContext = dirSelectOptions = new(); DataContext = dirSelectOptions = new();
} }
public void SaveButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public async void SaveButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{ {
var libationDir = dirSelectOptions.Directory; var libationDir = dirSelectOptions.Directory;
if (!System.IO.Directory.Exists(libationDir)) if (!System.IO.Directory.Exists(libationDir))
{ {
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, saveAndRestorePosition: false); 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, saveAndRestorePosition: false);
return; return;
} }

View File

@ -9,12 +9,12 @@ namespace LibationAvalonia.Dialogs.Login
{ {
/// <returns>True if ShowDialog's DialogResult == OK</returns> /// <returns>True if ShowDialog's DialogResult == OK</returns>
protected static bool ShowDialog(DialogWindow dialog) protected static async Task<bool> ShowDialog(DialogWindow dialog)
{ {
if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
return false; return false;
var result = dialog.ShowDialogSynchronously<DialogResult>(desktop.MainWindow); var result = await dialog.ShowDialog<DialogResult>(desktop.MainWindow);
Serilog.Log.Logger.Debug("{@DebugInfo}", new { DialogResult = result }); Serilog.Log.Logger.Debug("{@DebugInfo}", new { DialogResult = result });
return result == DialogResult.OK; return result == DialogResult.OK;
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Threading.Tasks;
using AudibleApi; using AudibleApi;
using AudibleUtilities; using AudibleUtilities;
@ -13,43 +14,43 @@ namespace LibationAvalonia.Dialogs.Login
_account = Dinah.Core.ArgumentValidator.EnsureNotNull(account, nameof(account)); _account = Dinah.Core.ArgumentValidator.EnsureNotNull(account, nameof(account));
} }
public string Get2faCode() public async Task<string> Get2faCodeAsync()
{ {
var dialog = new _2faCodeDialog(); var dialog = new _2faCodeDialog();
if (ShowDialog(dialog)) if (await ShowDialog(dialog))
return dialog.Code; return dialog.Code;
return null; return null;
} }
public string GetCaptchaAnswer(byte[] captchaImage) public async Task<string> GetCaptchaAnswerAsync(byte[] captchaImage)
{ {
var dialog = new CaptchaDialog(captchaImage); var dialog = new CaptchaDialog(captchaImage);
if (ShowDialog(dialog)) if (await ShowDialog(dialog))
return dialog.Answer; return dialog.Answer;
return null; return null;
} }
public (string name, string value) GetMfaChoice(MfaConfig mfaConfig) public async Task<(string name, string value)> GetMfaChoiceAsync(MfaConfig mfaConfig)
{ {
var dialog = new MfaDialog(mfaConfig); var dialog = new MfaDialog(mfaConfig);
if (ShowDialog(dialog)) if (await ShowDialog(dialog))
return (dialog.SelectedName, dialog.SelectedValue); return (dialog.SelectedName, dialog.SelectedValue);
return (null, null); return (null, null);
} }
public (string email, string password) GetLogin() public async Task<(string email, string password)> GetLoginAsync()
{ {
var dialog = new LoginCallbackDialog(_account); var dialog = new LoginCallbackDialog(_account);
if (ShowDialog(dialog)) if (await ShowDialog(dialog))
return (_account.AccountId, dialog.Password); return (_account.AccountId, dialog.Password);
return (null, null); return (null, null);
} }
public void ShowApprovalNeeded() public async Task ShowApprovalNeededAsync()
{ {
var dialog = new ApprovalNeededDialog(); var dialog = new ApprovalNeededDialog();
ShowDialog(dialog); await ShowDialog(dialog);
} }
} }
} }

View File

@ -20,11 +20,11 @@ namespace LibationAvalonia.Dialogs.Login
LoginCallback = new AvaloniaLoginCallback(_account); LoginCallback = new AvaloniaLoginCallback(_account);
} }
public ChoiceOut Start(ChoiceIn choiceIn) public async Task<ChoiceOut> StartAsync(ChoiceIn choiceIn)
{ {
var dialog = new LoginChoiceEagerDialog(_account); var dialog = new LoginChoiceEagerDialog(_account);
if (!ShowDialog(dialog)) if (!await ShowDialog(dialog))
return null; return null;
@ -35,7 +35,7 @@ namespace LibationAvalonia.Dialogs.Login
case LoginMethod.External: case LoginMethod.External:
{ {
var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl); var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl);
return ShowDialog(externalDialog) return await ShowDialog(externalDialog)
? ChoiceOut.External(externalDialog.ResponseUrl) ? ChoiceOut.External(externalDialog.ResponseUrl)
: null; : null;
} }
@ -43,5 +43,6 @@ namespace LibationAvalonia.Dialogs.Login
throw new Exception($"Unknown {nameof(LoginMethod)} value"); throw new Exception($"Unknown {nameof(LoginMethod)} value");
} }
} }
} }
} }

View File

@ -51,7 +51,7 @@ namespace LibationAvalonia.Dialogs.Login
Serilog.Log.Logger.Information("Submit button clicked: {@DebugInfo}", new { ResponseUrl }); Serilog.Log.Logger.Information("Submit button clicked: {@DebugInfo}", new { ResponseUrl });
if (!Uri.TryCreate(ResponseUrl, UriKind.Absolute, out var result)) if (!Uri.TryCreate(ResponseUrl, UriKind.Absolute, out var result))
{ {
MessageBox.Show("Invalid response URL"); await MessageBox.Show("Invalid response URL");
return; return;
} }
await base.SaveAndCloseAsync(); await base.SaveAndCloseAsync();

View File

@ -82,7 +82,7 @@ namespace LibationAvalonia.Dialogs.Login
}); });
if (selected is null) if (selected is null)
{ {
MessageBox.Show("No MFA option selected", "None selected", MessageBoxButtons.OK, MessageBoxIcon.Error); await MessageBox.Show("No MFA option selected", "None selected", MessageBoxButtons.OK, MessageBoxIcon.Error);
return; return;
} }

View File

@ -28,7 +28,7 @@ namespace LibationAvalonia.Dialogs
DataContext = this; DataContext = this;
} }
private void GoToGithub_Tapped(object sender, Avalonia.Interactivity.RoutedEventArgs e) private async void GoToGithub_Tapped(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{ {
var url = "https://github.com/rmcrackan/Libation/issues"; var url = "https://github.com/rmcrackan/Libation/issues";
try try
@ -37,11 +37,11 @@ namespace LibationAvalonia.Dialogs
} }
catch catch
{ {
MessageBox.Show($"Error opening url\r\n{url}", "Error opening url", MessageBoxButtons.OK, MessageBoxIcon.Error); await MessageBox.Show($"Error opening url\r\n{url}", "Error opening url", MessageBoxButtons.OK, MessageBoxIcon.Error);
} }
} }
private void GoToLogs_Tapped(object sender, Avalonia.Interactivity.RoutedEventArgs e) private async void GoToLogs_Tapped(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{ {
LongPath dir = ""; LongPath dir = "";
try try
@ -56,7 +56,7 @@ namespace LibationAvalonia.Dialogs
} }
catch catch
{ {
MessageBox.Show($"Error opening folder\r\n{dir}", "Error opening folder", MessageBoxButtons.OK, MessageBoxIcon.Error); await MessageBox.Show($"Error opening folder\r\n{dir}", "Error opening folder", MessageBoxButtons.OK, MessageBoxIcon.Error);
} }
} }

View File

@ -33,10 +33,10 @@ namespace LibationAvalonia.Dialogs
protected override async Task SaveAndCloseAsync() protected override async Task SaveAndCloseAsync()
{ {
if (!settingsDisp.SaveSettings(config)) if (!await settingsDisp.SaveSettingsAsync(config))
return; return;
MessageBox.VerboseLoggingWarning_ShowIfTrue(); await MessageBox.VerboseLoggingWarning_ShowIfTrue();
await base.SaveAndCloseAsync(); await base.SaveAndCloseAsync();
} }
@ -97,7 +97,7 @@ namespace LibationAvalonia.Dialogs
internal interface ISettingsDisplay internal interface ISettingsDisplay
{ {
void LoadSettings(Configuration config); void LoadSettings(Configuration config);
bool SaveSettings(Configuration config); Task<bool> SaveSettingsAsync(Configuration config);
} }
public class SettingsPages : ISettingsDisplay public class SettingsPages : ISettingsDisplay
@ -120,12 +120,12 @@ namespace LibationAvalonia.Dialogs
AudioSettings = new(config); AudioSettings = new(config);
} }
public bool SaveSettings(Configuration config) public async Task<bool> SaveSettingsAsync(Configuration config)
{ {
var result = ImportantSettings.SaveSettings(config); var result = await ImportantSettings.SaveSettingsAsync(config);
result &= ImportSettings.SaveSettings(config); result &= await ImportSettings.SaveSettingsAsync(config);
result &= DownloadDecryptSettings.SaveSettings(config); result &= await DownloadDecryptSettings.SaveSettingsAsync(config);
result &= AudioSettings.SaveSettings(config); result &= await AudioSettings.SaveSettingsAsync(config);
return result; return result;
} }
@ -146,13 +146,13 @@ namespace LibationAvalonia.Dialogs
BetaOptIn = config.BetaOptIn; BetaOptIn = config.BetaOptIn;
} }
public bool SaveSettings(Configuration config) public async Task<bool> SaveSettingsAsync(Configuration config)
{ {
#region validation #region validation
if (string.IsNullOrWhiteSpace(BooksDirectory)) if (string.IsNullOrWhiteSpace(BooksDirectory))
{ {
MessageBox.Show("Cannot set Books Location to blank", "Location is blank", MessageBoxButtons.OK, MessageBoxIcon.Error); await MessageBox.Show("Cannot set Books Location to blank", "Location is blank", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false; return false;
} }
@ -204,14 +204,14 @@ namespace LibationAvalonia.Dialogs
AutoDownloadEpisodes = config.AutoDownloadEpisodes; AutoDownloadEpisodes = config.AutoDownloadEpisodes;
} }
public bool SaveSettings(Configuration config) public Task<bool> SaveSettingsAsync(Configuration config)
{ {
config.AutoScan = AutoScan; config.AutoScan = AutoScan;
config.ShowImportedStats = ShowImportedStats; config.ShowImportedStats = ShowImportedStats;
config.ImportEpisodes = ImportEpisodes; config.ImportEpisodes = ImportEpisodes;
config.DownloadEpisodes = DownloadEpisodes; config.DownloadEpisodes = DownloadEpisodes;
config.AutoDownloadEpisodes = AutoDownloadEpisodes; config.AutoDownloadEpisodes = AutoDownloadEpisodes;
return true; return Task.FromResult(true);
} }
public string AutoScanText { get; } = Configuration.GetDescription(nameof(Configuration.AutoScan)); public string AutoScanText { get; } = Configuration.GetDescription(nameof(Configuration.AutoScan));
@ -259,25 +259,25 @@ namespace LibationAvalonia.Dialogs
: Configuration.GetKnownDirectory(config.InProgress); : Configuration.GetKnownDirectory(config.InProgress);
} }
public bool SaveSettings(Configuration config) public async Task<bool> SaveSettingsAsync(Configuration config)
{ {
static void validationError(string text, string caption) static Task validationError(string text, string caption)
=> MessageBox.Show(text, caption, MessageBoxButtons.OK, MessageBoxIcon.Error); => MessageBox.Show(text, caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
// these 3 should do nothing. Configuration will only init these with a valid value. EditTemplateDialog ensures valid before returning // these 3 should do nothing. Configuration will only init these with a valid value. EditTemplateDialog ensures valid before returning
if (!Templates.Folder.IsValid(FolderTemplate)) if (!Templates.Folder.IsValid(FolderTemplate))
{ {
validationError($"Not saving change to folder naming template. Invalid format.", "Invalid folder template"); await validationError($"Not saving change to folder naming template. Invalid format.", "Invalid folder template");
return false; return false;
} }
if (!Templates.File.IsValid(FileTemplate)) if (!Templates.File.IsValid(FileTemplate))
{ {
validationError($"Not saving change to file naming template. Invalid format.", "Invalid file template"); await validationError($"Not saving change to file naming template. Invalid format.", "Invalid file template");
return false; return false;
} }
if (!Templates.ChapterFile.IsValid(ChapterFileTemplate)) if (!Templates.ChapterFile.IsValid(ChapterFileTemplate))
{ {
validationError($"Not saving change to chapter file naming template. Invalid format.", "Invalid chapter file template"); await validationError($"Not saving change to chapter file naming template. Invalid format.", "Invalid chapter file template");
return false; return false;
} }
@ -405,7 +405,7 @@ namespace LibationAvalonia.Dialogs
LameVBRQuality = config.LameVBRQuality; LameVBRQuality = config.LameVBRQuality;
} }
public bool SaveSettings(Configuration config) public Task<bool> SaveSettingsAsync(Configuration config)
{ {
config.CreateCueSheet = CreateCueSheet; config.CreateCueSheet = CreateCueSheet;
config.AllowLibationFixup = AllowLibationFixup; config.AllowLibationFixup = AllowLibationFixup;
@ -424,7 +424,7 @@ namespace LibationAvalonia.Dialogs
config.LameBitrate = LameBitrate; config.LameBitrate = LameBitrate;
config.LameVBRQuality = LameVBRQuality; config.LameVBRQuality = LameVBRQuality;
return true; return Task.FromResult(true);
} }
public string CreateCueSheetText { get; } = Configuration.GetDescription(nameof(Configuration.CreateCueSheet)); public string CreateCueSheetText { get; } = Configuration.GetDescription(nameof(Configuration.CreateCueSheet));

View File

@ -81,8 +81,6 @@
<None Remove="Assets\SEGOEUI.TTF" /> <None Remove="Assets\SEGOEUI.TTF" />
<None Remove="Assets\up.png" /> <None Remove="Assets\up.png" />
<None Remove="Assets\WINGDING.TTF" /> <None Remove="Assets\WINGDING.TTF" />
<None Remove="MessageBox.cs~RF105afb8d.TMP" />
<None Remove="Views\MainWindow\MainWindow.Export.axaml.cs~RF10732d95.TMP" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -62,34 +62,34 @@ namespace LibationAvalonia
public class MessageBox public class MessageBox
{ {
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) public static Task<DialogResult> Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
=> ShowCoreAsync(null, text, caption, buttons, icon, defaultButton); => ShowCoreAsync(null, text, caption, buttons, icon, defaultButton);
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, bool saveAndRestorePosition = true) public static Task<DialogResult> Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, bool saveAndRestorePosition = true)
=> ShowCoreAsync(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1, saveAndRestorePosition); => ShowCoreAsync(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1, saveAndRestorePosition);
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons) public static Task<DialogResult> Show(string text, string caption, MessageBoxButtons buttons)
=> ShowCoreAsync(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); => ShowCoreAsync(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
public static DialogResult Show(string text, string caption) public static Task<DialogResult> Show(string text, string caption)
=> ShowCoreAsync(null, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); => ShowCoreAsync(null, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
public static DialogResult Show(string text) public static Task<DialogResult> Show(string text)
=> ShowCoreAsync(null, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); => ShowCoreAsync(null, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
public static DialogResult Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) public static Task<DialogResult> Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
=> ShowCoreAsync(owner, text, caption, buttons, icon, defaultButton); => ShowCoreAsync(owner, text, caption, buttons, icon, defaultButton);
public static DialogResult Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) public static Task<DialogResult> Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
=> ShowCoreAsync(owner, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); => ShowCoreAsync(owner, text, caption, buttons, icon, MessageBoxDefaultButton.Button1);
public static DialogResult Show(Window owner, string text, string caption, MessageBoxButtons buttons) public static Task<DialogResult> Show(Window owner, string text, string caption, MessageBoxButtons buttons)
=> ShowCoreAsync(owner, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); => ShowCoreAsync(owner, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
public static DialogResult Show(Window owner, string text, string caption) public static Task<DialogResult> Show(Window owner, string text, string caption)
=> ShowCoreAsync(owner, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); => ShowCoreAsync(owner, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
public static DialogResult Show(Window owner, string text) public static Task<DialogResult> Show(Window owner, string text)
=> ShowCoreAsync(owner, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); => ShowCoreAsync(owner, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
public static void VerboseLoggingWarning_ShowIfTrue() public static async Task VerboseLoggingWarning_ShowIfTrue()
{ {
// when turning on debug (and especially Verbose) to share logs, some privacy settings may not be obscured // when turning on debug (and especially Verbose) to share logs, some privacy settings may not be obscured
if (Serilog.Log.Logger.IsVerboseEnabled()) if (Serilog.Log.Logger.IsVerboseEnabled())
Show(@" await Show(@"
Warning: verbose logging is enabled. Warning: verbose logging is enabled.
This should be used for debugging only. It creates many This should be used for debugging only. It creates many
@ -102,7 +102,7 @@ Libation.
".Trim(), "Verbose logging enabled", MessageBoxButtons.OK, MessageBoxIcon.Warning); ".Trim(), "Verbose logging enabled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
} }
public static DialogResult ShowConfirmationDialog(Window owner, IEnumerable<LibraryBook> libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) public static async Task<DialogResult> ShowConfirmationDialog(Window owner, IEnumerable<LibraryBook> libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1)
{ {
if (libraryBooks is null || !libraryBooks.Any()) if (libraryBooks is null || !libraryBooks.Any())
return DialogResult.Cancel; return DialogResult.Cancel;
@ -117,7 +117,7 @@ Libation.
= string.Format(format, $"{thisThese} {count} {bookBooks}") = string.Format(format, $"{thisThese} {count} {bookBooks}")
+ $"\r\n\r\n{titlesAgg}"; + $"\r\n\r\n{titlesAgg}";
return ShowCoreAsync(owner, return await ShowCoreAsync(owner,
message, message,
title, title,
MessageBoxButtons.YesNo, MessageBoxButtons.YesNo,
@ -132,7 +132,7 @@ Libation.
/// <param name="text">The text to display in the message box.</param> /// <param name="text">The text to display in the message box.</param>
/// <param name="caption">The text to display in the title bar of the message box.</param> /// <param name="caption">The text to display in the title bar of the message box.</param>
/// <param name="exception">Exception to log.</param> /// <param name="exception">Exception to log.</param>
public static void ShowAdminAlert(Window owner, string text, string caption, Exception exception) public static async Task ShowAdminAlert(Window owner, string text, string caption, Exception exception)
{ {
// for development and debugging, show me what broke! // for development and debugging, show me what broke!
if (System.Diagnostics.Debugger.IsAttached) if (System.Diagnostics.Debugger.IsAttached)
@ -146,14 +146,14 @@ Libation.
var form = new MessageBoxAlertAdminDialog(text, caption, exception); var form = new MessageBoxAlertAdminDialog(text, caption, exception);
DisplayWindow(form, owner); await DisplayWindow(form, owner);
} }
private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) private static async Task<DialogResult> ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true)
{ {
var dialog = Dispatcher.UIThread.Invoke(() => CreateMessageBox(owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition)); var dialog = await Dispatcher.UIThread.InvokeAsync(() => CreateMessageBox(owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition));
return DisplayWindow(dialog, owner); return await DisplayWindow(dialog, owner);
} }
private static MessageBoxWindow CreateMessageBox(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) private static MessageBoxWindow CreateMessageBox(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true)
@ -192,13 +192,13 @@ Libation.
dialog.Width = dialog.MinWidth; dialog.Width = dialog.MinWidth;
return dialog; return dialog;
} }
private static DialogResult DisplayWindow(Window toDisplay, Window owner) private static async Task<DialogResult> DisplayWindow(Window toDisplay, Window owner)
{ {
if (owner is null) if (owner is null)
{ {
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
return toDisplay.ShowDialogSynchronously<DialogResult>(desktop.MainWindow); return await toDisplay.ShowDialog<DialogResult>(desktop.MainWindow);
} }
else else
{ {
@ -212,7 +212,7 @@ Libation.
}; };
window.Show(); window.Show();
var result = toDisplay.ShowDialogSynchronously<DialogResult>(window); var result = await toDisplay.ShowDialog<DialogResult>(window);
window.Close(); window.Close();
return result; return result;
} }
@ -220,7 +220,7 @@ Libation.
} }
else else
{ {
return toDisplay.ShowDialogSynchronously<DialogResult>(owner); return await toDisplay.ShowDialog<DialogResult>(owner);
} }
} }

View File

@ -14,7 +14,7 @@ namespace LibationAvalonia
{ {
private static string EXE_DIR = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); private static string EXE_DIR = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
static async Task Main() static void Main()
{ {
//***********************************************// //***********************************************//
// // // //
@ -47,9 +47,7 @@ namespace LibationAvalonia
App.LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true)); App.LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true));
} }
(appBuilderTask.GetAwaiter().GetResult()).SetupWithLifetime(classicLifetimeTask.GetAwaiter().GetResult());
(await appBuilderTask).SetupWithLifetime(await classicLifetimeTask);
classicLifetimeTask.Result.Start(null); classicLifetimeTask.Result.Start(null);
} }

View File

@ -152,7 +152,7 @@ namespace LibationAvalonia.ViewModels
finally finally
{ {
if (Result == ProcessBookResult.None) if (Result == ProcessBookResult.None)
Result = showRetry(LibraryBook); Result = await showRetry(LibraryBook);
Status = Result switch Status = Result switch
{ {
@ -313,7 +313,7 @@ namespace LibationAvalonia.ViewModels
#region Failure Handler #region Failure Handler
private ProcessBookResult showRetry(LibraryBook libraryBook) private async Task<ProcessBookResult> showRetry(LibraryBook libraryBook)
{ {
Logger.Error("ERROR. All books have not been processed. Most recent book: processing failed"); Logger.Error("ERROR. All books have not been processed. Most recent book: processing failed");
@ -346,7 +346,7 @@ $@" Title: {libraryBook.Book.Title}
} }
// if null then ask user // if null then ask user
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); 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);
if (dialogResult == DialogResult.Abort) if (dialogResult == DialogResult.Abort)
return ProcessBookResult.FailedAbort; return ProcessBookResult.FailedAbort;

View File

@ -244,7 +244,7 @@ namespace LibationAvalonia.ViewModels
return; return;
var libraryBooks = selectedBooks.Select(rge => rge.LibraryBook).ToList(); var libraryBooks = selectedBooks.Select(rge => rge.LibraryBook).ToList();
var result = MessageBox.ShowConfirmationDialog( var result = await MessageBox.ShowConfirmationDialog(
null, null,
libraryBooks, libraryBooks,
$"Are you sure you want to remove {selectedBooks.Count} books from Libation's library?", $"Are you sure you want to remove {selectedBooks.Count} books from Libation's library?",
@ -317,7 +317,7 @@ namespace LibationAvalonia.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.ShowAdminAlert( await MessageBox.ShowAdminAlert(
null, null,
"Error scanning library. You may still manually select books to remove from Libation's library.", "Error scanning library. You may still manually select books to remove from Libation's library.",
"Error scanning library", "Error scanning library",

View File

@ -41,11 +41,11 @@ namespace LibationAvalonia.Views
break; break;
} }
MessageBox.Show("Library exported to:\r\n" + fileName, "Library Exported"); await MessageBox.Show("Library exported to:\r\n" + fileName, "Library Exported");
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.ShowAdminAlert(this, "Error attempting to export your library.", "Error exporting", ex); await MessageBox.ShowAdminAlert(this, "Error attempting to export your library.", "Error exporting", ex);
} }
} }
} }

View File

@ -39,7 +39,7 @@ namespace LibationAvalonia.Views
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show($"Bad filter string:\r\n\r\n{ex.Message}", "Bad filter string", MessageBoxButtons.OK, MessageBoxIcon.Error); await MessageBox.Show($"Bad filter string:\r\n\r\n{ex.Message}", "Bad filter string", MessageBoxButtons.OK, MessageBoxIcon.Error);
// re-apply last good filter // re-apply last good filter
await performFilter(lastGoodFilter); await performFilter(lastGoodFilter);

View File

@ -40,7 +40,7 @@ namespace LibationAvalonia.Views
public async void convertAllM4bToMp3ToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) public async void convertAllM4bToMp3ToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
{ {
var result = MessageBox.Show( var result = await MessageBox.Show(
"This converts all m4b titles in your library to mp3 files. Original files are not deleted." "This converts all m4b titles in your library to mp3 files. Original files are not deleted."
+ "\r\nFor large libraries this will take a long time and will take up more disk space." + "\r\nFor large libraries this will take a long time and will take up more disk space."
+ "\r\n\r\nContinue?" + "\r\n\r\nContinue?"

View File

@ -15,7 +15,7 @@ namespace LibationAvalonia.Views
SetQueueCollapseState(collapseState); SetQueueCollapseState(collapseState);
} }
public void ProductsDisplay_LiberateClicked(object sender, LibraryBook libraryBook) public async void ProductsDisplay_LiberateClicked(object sender, LibraryBook libraryBook)
{ {
try try
{ {
@ -39,7 +39,7 @@ namespace LibationAvalonia.Views
if (!App.GoToFile(filePath?.ShortPathName)) if (!App.GoToFile(filePath?.ShortPathName))
{ {
var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}"; var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}";
MessageBox.Show($"File not found" + suffix); await MessageBox.Show($"File not found" + suffix);
} }
} }
} }

View File

@ -26,7 +26,7 @@ namespace LibationAvalonia.Views
public async void noAccountsYetAddAccountToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public async void noAccountsYetAddAccountToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{ {
MessageBox.Show("To load your Audible library, come back here to the Import menu after adding your account"); await MessageBox.Show("To load your Audible library, come back here to the Import menu after adding your account");
await new Dialogs.AccountsDialog().ShowDialog(this); await new Dialogs.AccountsDialog().ShowDialog(this);
} }
@ -66,11 +66,11 @@ namespace LibationAvalonia.Views
// this is here instead of ScanEnd so that the following is only possible when it's user-initiated, not automatic loop // this is here instead of ScanEnd so that the following is only possible when it's user-initiated, not automatic loop
if (Configuration.Instance.ShowImportedStats && newAdded > 0) if (Configuration.Instance.ShowImportedStats && newAdded > 0)
MessageBox.Show($"Total processed: {totalProcessed}\r\nNew: {newAdded}"); await MessageBox.Show($"Total processed: {totalProcessed}\r\nNew: {newAdded}");
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.ShowAdminAlert( await MessageBox.ShowAdminAlert(
this, this,
"Error importing library. Please try again. If this still happens after 2 or 3 tries, stop and contact administrator", "Error importing library. Please try again. If this still happens after 2 or 3 tries, stop and contact administrator",
"Error importing library", "Error importing library",

View File

@ -8,11 +8,13 @@ namespace LibationAvalonia.Views
{ {
private void Configure_Settings() { } private void Configure_Settings() { }
public async void accountsToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) => await new Dialogs.AccountsDialog().ShowDialog(this); public async void accountsToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> await new Dialogs.AccountsDialog().ShowDialog(this);
public async void basicSettingsToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) => await new Dialogs.SettingsDialog().ShowDialog(this); public async void basicSettingsToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> await new Dialogs.SettingsDialog().ShowDialog(this);
public void aboutToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public async void aboutToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> MessageBox.Show($"Running Libation version {AppScaffolding.LibationScaffolding.BuildVersion}", $"Libation v{AppScaffolding.LibationScaffolding.BuildVersion}"); => await MessageBox.Show($"Running Libation version {AppScaffolding.LibationScaffolding.BuildVersion}", $"Libation v{AppScaffolding.LibationScaffolding.BuildVersion}");
} }
} }

View File

@ -47,7 +47,7 @@ namespace LibationAvalonia.Views
var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries(); var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries();
var confirmationResult = MessageBox.ShowConfirmationDialog( var confirmationResult = await MessageBox.ShowConfirmationDialog(
this, this,
visibleLibraryBooks, visibleLibraryBooks,
"Are you sure you want to replace tags in {0}?", "Are you sure you want to replace tags in {0}?",
@ -70,7 +70,7 @@ namespace LibationAvalonia.Views
var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries(); var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries();
var confirmationResult = MessageBox.ShowConfirmationDialog( var confirmationResult = await MessageBox.ShowConfirmationDialog(
this, this,
visibleLibraryBooks, visibleLibraryBooks,
"Are you sure you want to replace downloaded status in {0}?", "Are you sure you want to replace downloaded status in {0}?",
@ -88,7 +88,7 @@ namespace LibationAvalonia.Views
{ {
var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries(); var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries();
var confirmationResult = MessageBox.ShowConfirmationDialog( var confirmationResult = await MessageBox.ShowConfirmationDialog(
this, this,
visibleLibraryBooks, visibleLibraryBooks,
"Are you sure you want to remove {0} from Libation's library?", "Are you sure you want to remove {0} from Libation's library?",

View File

@ -80,7 +80,7 @@ namespace LibationAvalonia.Views
if (string.IsNullOrEmpty(zipFile) || !System.IO.File.Exists(zipFile)) if (string.IsNullOrEmpty(zipFile) || !System.IO.File.Exists(zipFile))
return; return;
var result = MessageBox.Show($"{upgradeProperties.HtmlUrl}\r\n\r\nWould you like to upgrade now?", "New version available", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); var result = await MessageBox.Show($"{upgradeProperties.HtmlUrl}\r\n\r\nWould you like to upgrade now?", "New version available", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if (result != DialogResult.Yes) if (result != DialogResult.Yes)
return; return;

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Threading.Tasks;
using AudibleApi; using AudibleApi;
using AudibleUtilities; using AudibleUtilities;
using LibationWinForms.Dialogs.Login; using LibationWinForms.Dialogs.Login;
@ -14,42 +15,43 @@ namespace LibationWinForms.Login
_account = Dinah.Core.ArgumentValidator.EnsureNotNull(account, nameof(account)); _account = Dinah.Core.ArgumentValidator.EnsureNotNull(account, nameof(account));
} }
public string Get2faCode() public Task<string> Get2faCodeAsync()
{ {
using var dialog = new _2faCodeDialog(); using var dialog = new _2faCodeDialog();
if (ShowDialog(dialog)) if (ShowDialog(dialog))
return dialog.Code; return Task.FromResult(dialog.Code);
return null; return Task.FromResult<string>(null);
} }
public string GetCaptchaAnswer(byte[] captchaImage) public Task<string> GetCaptchaAnswerAsync(byte[] captchaImage)
{ {
using var dialog = new CaptchaDialog(captchaImage); using var dialog = new CaptchaDialog(captchaImage);
if (ShowDialog(dialog)) if (ShowDialog(dialog))
return dialog.Answer; return Task.FromResult(dialog.Answer);
return null; return Task.FromResult<string>(null);
} }
public (string name, string value) GetMfaChoice(MfaConfig mfaConfig) public Task<(string name, string value)> GetMfaChoiceAsync(MfaConfig mfaConfig)
{ {
using var dialog = new MfaDialog(mfaConfig); using var dialog = new MfaDialog(mfaConfig);
if (ShowDialog(dialog)) if (ShowDialog(dialog))
return (dialog.SelectedName, dialog.SelectedValue); return Task.FromResult((dialog.SelectedName, dialog.SelectedValue));
return (null, null); return Task.FromResult<(string, string)>((null, null));
} }
public (string email, string password) GetLogin() public Task<(string email, string password)> GetLoginAsync()
{ {
using var dialog = new LoginCallbackDialog(_account); using var dialog = new LoginCallbackDialog(_account);
if (ShowDialog(dialog)) if (ShowDialog(dialog))
return (dialog.Email, dialog.Password); return Task.FromResult((dialog.Email, dialog.Password));
return (null, null); return Task.FromResult<(string, string)>((null, null));
} }
public void ShowApprovalNeeded() public Task ShowApprovalNeededAsync()
{ {
using var dialog = new ApprovalNeededDialog(); using var dialog = new ApprovalNeededDialog();
ShowDialog(dialog); ShowDialog(dialog);
return Task.CompletedTask;
} }
} }
} }

View File

@ -21,7 +21,7 @@ namespace LibationWinForms.Login
LoginCallback = new WinformLoginCallback(_account); LoginCallback = new WinformLoginCallback(_account);
} }
public ChoiceOut Start(ChoiceIn choiceIn) public Task<ChoiceOut> StartAsync(ChoiceIn choiceIn)
{ {
using var dialog = new LoginChoiceEagerDialog(_account); using var dialog = new LoginChoiceEagerDialog(_account);
@ -31,13 +31,14 @@ namespace LibationWinForms.Login
switch (dialog.LoginMethod) switch (dialog.LoginMethod)
{ {
case LoginMethod.Api: case LoginMethod.Api:
return ChoiceOut.WithApi(dialog.Email, dialog.Password); return Task.FromResult(ChoiceOut.WithApi(dialog.Email, dialog.Password));
case LoginMethod.External: case LoginMethod.External:
{ {
using var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl); using var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl);
return ShowDialog(externalDialog) return Task.FromResult(
ShowDialog(externalDialog)
? ChoiceOut.External(externalDialog.ResponseUrl) ? ChoiceOut.External(externalDialog.ResponseUrl)
: null; : null);
} }
default: default:
throw new Exception($"Unknown {nameof(LoginMethod)} value"); throw new Exception($"Unknown {nameof(LoginMethod)} value");