diff --git a/Source/AppScaffolding/AppScaffolding.csproj b/Source/AppScaffolding/AppScaffolding.csproj index 91ae4d61..06e37351 100644 --- a/Source/AppScaffolding/AppScaffolding.csproj +++ b/Source/AppScaffolding/AppScaffolding.csproj @@ -11,6 +11,13 @@ + + + $(DefineConstants);WINDOWS + $(DefineConstants);LINUX + $(DefineConstants);MACOS + + embedded diff --git a/Source/AppScaffolding/LibationScaffolding.cs b/Source/AppScaffolding/LibationScaffolding.cs index 33f385c7..56f6e781 100644 --- a/Source/AppScaffolding/LibationScaffolding.cs +++ b/Source/AppScaffolding/LibationScaffolding.cs @@ -14,8 +14,23 @@ using Serilog; namespace AppScaffolding { + + public enum ReleaseIdentifier + { + None, + WindowsClassic, + WindowsAvalonia, + LinuxAvalonia, + MacOSAvalonia + } + public static class LibationScaffolding { + public static ReleaseIdentifier ReleaseIdentifier { get; private set; } + + public static void SetReleaseIdentifier(ReleaseIdentifier releaseID) + => ReleaseIdentifier = releaseID; + // AppScaffolding private static Assembly _executingAssembly; private static Assembly ExecutingAssembly @@ -275,12 +290,23 @@ namespace AppScaffolding if (System.Diagnostics.Debugger.IsAttached) mode += " (Debugger attached)"; +#if MACOS + var os = "MacOS"; +#elif LINUX + var os = "Linux"; +#else + var os = "Windows"; +#endif + + // begin logging session with a form feed Log.Logger.Information("\r\n\f"); Log.Logger.Information("Begin. {@DebugInfo}", new { AppName = EntryAssembly.GetName().Name, Version = BuildVersion.ToString(), + ReleaseIdentifier = ReleaseIdentifier, + OS = os, Mode = mode, LogLevel_Verbose_Enabled = Log.Logger.IsVerboseEnabled(), LogLevel_Debug_Enabled = Log.Logger.IsDebugEnabled(), @@ -309,18 +335,10 @@ namespace AppScaffolding LibraryCommands.BookUserDefinedItemCommitted += (_, books) => SearchEngineCommands.UpdateBooks(books); } - public enum ReleaseIdentifier - { - WindowsClassic, - WindowsAvalonia, - LinuxAvalonia, - MacOSAvalonia - } - - public static UpgradeProperties GetLatestRelease(ReleaseIdentifier releaseID = ReleaseIdentifier.WindowsClassic) + public static UpgradeProperties GetLatestRelease() { // timed out - (var latest, var zip) = getLatestRelease(TimeSpan.FromSeconds(10), releaseID); + (var latest, var zip) = getLatestRelease(TimeSpan.FromSeconds(10)); if (latest is null || zip is null) return null; @@ -346,11 +364,11 @@ namespace AppScaffolding return new(zipUrl, latest.HtmlUrl, zip.Name, latestRelease); } - private static (Octokit.Release, Octokit.ReleaseAsset) getLatestRelease(TimeSpan timeout, ReleaseIdentifier releaseID) + private static (Octokit.Release, Octokit.ReleaseAsset) getLatestRelease(TimeSpan timeout) { try { - var task = getLatestRelease(releaseID); + var task = getLatestRelease(); if (task.Wait(timeout)) return task.Result; @@ -362,7 +380,7 @@ namespace AppScaffolding } return (null, null); } - private static async System.Threading.Tasks.Task<(Octokit.Release, Octokit.ReleaseAsset)> getLatestRelease(ReleaseIdentifier releaseID) + private static async System.Threading.Tasks.Task<(Octokit.Release, Octokit.ReleaseAsset)> getLatestRelease() { var ownerAccount = "rmcrackan"; var repoName = "Libation"; @@ -372,7 +390,7 @@ namespace AppScaffolding //Download the release index var bts = await gitHubClient.Repository.Content.GetRawContent(ownerAccount, repoName, ".releaseindex.json"); var releaseIndex = JObject.Parse(System.Text.Encoding.ASCII.GetString(bts)); - var regexPattern = releaseIndex.Value(releaseID.ToString()); + var regexPattern = releaseIndex.Value(ReleaseIdentifier.ToString()); // https://octokitnet.readthedocs.io/en/latest/releases/ var releases = await gitHubClient.Repository.Release.GetAll(ownerAccount, repoName); diff --git a/Source/Hangover/Hangover.csproj b/Source/Hangover/Hangover.csproj index f0f94038..6e87340d 100644 --- a/Source/Hangover/Hangover.csproj +++ b/Source/Hangover/Hangover.csproj @@ -6,6 +6,7 @@ true hangover.ico enable + true true win-x64 false @@ -54,4 +55,11 @@ + + + + + + + \ No newline at end of file diff --git a/Source/Hangover/Properties/PublishProfiles/WindowsProfile.pubxml b/Source/Hangover/Properties/PublishProfiles/WindowsProfile.pubxml index 796e806b..bdb7559e 100644 --- a/Source/Hangover/Properties/PublishProfiles/WindowsProfile.pubxml +++ b/Source/Hangover/Properties/PublishProfiles/WindowsProfile.pubxml @@ -12,5 +12,6 @@ https://go.microsoft.com/fwlink/?LinkID=208121. win-x64 true false + false \ No newline at end of file diff --git a/Source/LibationAvalonia/App.axaml.cs b/Source/LibationAvalonia/App.axaml.cs index 8d806fc8..a3f0b2a4 100644 --- a/Source/LibationAvalonia/App.axaml.cs +++ b/Source/LibationAvalonia/App.axaml.cs @@ -17,10 +17,16 @@ namespace LibationAvalonia { public class App : Application { - public static bool IsWindows => PlatformID is PlatformID.Win32NT; - public static bool IsUnix => PlatformID is PlatformID.Unix; + public static readonly bool IsWindows; + public static readonly bool IsLinux; + public static readonly bool IsMacOs; + static App() + { + IsWindows = OperatingSystem.IsWindows(); + IsLinux = OperatingSystem.IsLinux(); + IsMacOs = OperatingSystem.IsMacOS(); + } - public static readonly PlatformID PlatformID = Environment.OSVersion.Platform; public static IBrush ProcessQueueBookFailedBrush { get; private set; } public static IBrush ProcessQueueBookCompletedBrush { get; private set; } public static IBrush ProcessQueueBookCancelledBrush { get; private set; } @@ -29,20 +35,20 @@ namespace LibationAvalonia public static IAssetLoader AssetLoader { get; private set; } - public static readonly Uri AssetUriBase = new Uri("avares://Libation/Assets/"); + public static readonly Uri AssetUriBase = new("avares://Libation/Assets/"); public static Stream OpenAsset(string assetRelativePath) => AssetLoader.Open(new Uri(AssetUriBase, assetRelativePath)); public static bool GoToFile(string path) - => PlatformID is PlatformID.Win32NT ? Go.To.File(path) + => IsWindows ? Go.To.File(path) : GoToFolder(path is null ? string.Empty : Path.GetDirectoryName(path)); public static bool GoToFolder(string path) { - if (PlatformID is PlatformID.Win32NT) + if (IsWindows) return Go.To.Folder(path); - else + else if (IsLinux) { var startInfo = new System.Diagnostics.ProcessStartInfo() { @@ -56,6 +62,8 @@ namespace LibationAvalonia System.Diagnostics.Process.Start(startInfo); return true; } + //Don't know how to do this for mac yet + else return true; } public override void Initialize() @@ -107,7 +115,7 @@ namespace LibationAvalonia 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 desktop = ApplicationLifetime as IClassicDesktopStyleApplicationLifetime; @@ -120,9 +128,9 @@ namespace LibationAvalonia if ((!setupDialog.IsNewUser && !setupDialog.IsReturningUser) || - !RunInstall(setupDialog)) + !await RunInstall(setupDialog)) { - CancelInstallation(); + await CancelInstallation(); return; } @@ -130,7 +138,7 @@ namespace LibationAvalonia // most migrations go in here AppScaffolding.LibationScaffolding.RunPostConfigMigrations(setupDialog.Config); - MessageBox.VerboseLoggingWarning_ShowIfTrue(); + await MessageBox.VerboseLoggingWarning_ShowIfTrue(); #if !DEBUG //AutoUpdater.NET only works for WinForms or WPF application projects. @@ -146,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."; try { - MessageBox.ShowAdminAlert(null, body, title, ex); + await MessageBox.ShowAdminAlert(null, body, title, ex); } 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; } @@ -160,7 +168,7 @@ namespace LibationAvalonia ShowMainWindow(desktop); } - private static bool RunInstall(SetupDialog setupDialog) + private static async Task RunInstall(SetupDialog setupDialog) { var config = setupDialog.Config; @@ -173,7 +181,7 @@ namespace LibationAvalonia var libationFilesDialog = new LibationFilesDialog(); - if (libationFilesDialog.ShowDialogSynchronously(setupDialog) != DialogResult.OK) + if (await libationFilesDialog.ShowDialog(setupDialog) != DialogResult.OK) return false; config.SetLibationFiles(libationFilesDialog.SelectedDirectory); @@ -181,7 +189,7 @@ namespace LibationAvalonia return true; // 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}", "New install?", MessageBoxButtons.YesNo, @@ -196,13 +204,13 @@ namespace LibationAvalonia config.Books ??= Path.Combine(Configuration.UserProfile, "Books"); AppScaffolding.LibationScaffolding.PopulateMissingConfigValues(config); - return new SettingsDialog().ShowDialogSynchronously(setupDialog) == DialogResult.OK + return await new SettingsDialog().ShowDialog(setupDialog) == DialogResult.OK && 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); } @@ -225,4 +233,4 @@ namespace LibationAvalonia SeriesEntryGridBackgroundBrush = AvaloniaUtils.GetBrushFromResources("SeriesEntryGridBackgroundBrush"); } } -} \ No newline at end of file +} diff --git a/Source/LibationAvalonia/AvaloniaThreadUtils.cs b/Source/LibationAvalonia/AvaloniaThreadUtils.cs deleted file mode 100644 index b5683223..00000000 --- a/Source/LibationAvalonia/AvaloniaThreadUtils.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Avalonia.Threading -{ - internal static class AvaloniaThreadUtils - { - public static TResult Invoke(this Dispatcher dispatcher, Func 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(this Task 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); - } - } -} diff --git a/Source/LibationAvalonia/AvaloniaUtils.cs b/Source/LibationAvalonia/AvaloniaUtils.cs index 906bfe61..3baee64e 100644 --- a/Source/LibationAvalonia/AvaloniaUtils.cs +++ b/Source/LibationAvalonia/AvaloniaUtils.cs @@ -16,10 +16,5 @@ namespace LibationAvalonia return brush; return defaultBrush; } - - public static T ShowDialogSynchronously(this Avalonia.Controls.Window window, Avalonia.Controls.Window owner) - { - return window.ShowDialog(owner).WaitOnDispatcherAndGetResult(Dispatcher.UIThread); - } } } diff --git a/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml.cs b/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml.cs index 6002753d..02b85fe6 100644 --- a/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml.cs +++ b/Source/LibationAvalonia/Controls/DirectoryOrCustomSelectControl.axaml.cs @@ -38,6 +38,7 @@ namespace LibationAvalonia.Controls set => SetValue(SubDirectoryProperty, value); } CustomState customStates = new(); + public DirectoryOrCustomSelectControl() { InitializeComponent(); @@ -53,9 +54,8 @@ namespace LibationAvalonia.Controls customDirBrowseBtn.Click += CustomDirBrowseBtn_Click; PropertyChanged += DirectoryOrCustomSelectControl_PropertyChanged; directorySelectControl.PropertyChanged += DirectorySelectControl_PropertyChanged; - - } + private class CustomState: ViewModels.ViewModelBase { private string _customDir; @@ -116,12 +116,13 @@ namespace LibationAvalonia.Controls private void setDirectory() { - var path1 + var selectedDir = 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); + selectedDir ??= string.Empty; + + Directory = customStates.CustomChecked ? selectedDir : System.IO.Path.Combine(selectedDir, SubDirectory); } @@ -140,7 +141,7 @@ namespace LibationAvalonia.Controls if (known is Configuration.KnownDirectories.None) { customStates.CustomChecked = true; - customStates.CustomDir = noSubDir; + customStates.CustomDir = directory; } else { diff --git a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs index eb2e466c..8020436c 100644 --- a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs @@ -136,7 +136,7 @@ namespace LibationAvalonia.Dialogs 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; } @@ -146,7 +146,7 @@ namespace LibationAvalonia.Dialogs } catch (Exception ex) { - MessageBox.ShowAdminAlert( + await 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", @@ -160,11 +160,11 @@ namespace LibationAvalonia.Dialogs Export(acc); } - protected override void SaveAndClose() + protected override async Task SaveAndCloseAsync() { try { - if (!inputIsValid()) + if (!await inputIsValid()) return; // without transaction, accounts persister will write ANY EDIT immediately to file @@ -178,7 +178,7 @@ namespace LibationAvalonia.Dialogs } 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(); } } - private bool inputIsValid() + private async Task inputIsValid() { foreach (var dto in Accounts.ToList()) { @@ -233,13 +233,13 @@ namespace LibationAvalonia.Dialogs 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; } 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; } } @@ -259,7 +259,7 @@ namespace LibationAvalonia.Dialogs 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; } @@ -282,11 +282,11 @@ namespace LibationAvalonia.Dialogs 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) { - MessageBox.ShowAdminAlert( + await MessageBox.ShowAdminAlert( this, $"An error occurred while exporting account:\r\n{account.AccountName}", "Error Exporting Account", diff --git a/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs index f5846da3..c3b15ba4 100644 --- a/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs @@ -64,7 +64,7 @@ namespace LibationAvalonia.Dialogs } protected override async Task SaveAndCloseAsync() { - if (!_viewModel.Validate()) + if (!await _viewModel.Validate()) return; TemplateText = _viewModel.workingTemplateText; @@ -115,7 +115,7 @@ namespace LibationAvalonia.Dialogs public void resetTextBox(string value) => workingTemplateText = value; - public bool Validate() + public async Task Validate() { if (template.IsValid(workingTemplateText)) return true; @@ -123,7 +123,7 @@ namespace LibationAvalonia.Dialogs .GetErrors(workingTemplateText) .Select(err => $"- {err}") .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; } diff --git a/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs index 5ca1722b..9bd7f398 100644 --- a/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs @@ -51,7 +51,7 @@ namespace LibationAvalonia.Dialogs saveFileDialog.Filters.Add(new FileDialogFilter { Name = "Jpeg", Extensions = new System.Collections.Generic.List() { "jpg" } }); saveFileDialog.InitialFileName = PictureFileName; saveFileDialog.Directory - = App.IsUnix ? null + = !App.IsWindows ? null : Directory.Exists(BookSaveDirectory) ? BookSaveDirectory : Path.GetDirectoryName(BookSaveDirectory); @@ -67,7 +67,7 @@ namespace LibationAvalonia.Dialogs catch (Exception ex) { 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); } } diff --git a/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml.cs index 19778842..a1ba044f 100644 --- a/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml.cs @@ -33,14 +33,14 @@ namespace LibationAvalonia.Dialogs 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; 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; } diff --git a/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginBase.cs b/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginBase.cs index 2ebfae9e..276ee9b8 100644 --- a/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginBase.cs +++ b/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginBase.cs @@ -9,12 +9,12 @@ namespace LibationAvalonia.Dialogs.Login { /// True if ShowDialog's DialogResult == OK - protected static bool ShowDialog(DialogWindow dialog) + protected static async Task ShowDialog(DialogWindow dialog) { if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return false; - var result = dialog.ShowDialogSynchronously(desktop.MainWindow); + var result = await dialog.ShowDialog(desktop.MainWindow); Serilog.Log.Logger.Debug("{@DebugInfo}", new { DialogResult = result }); return result == DialogResult.OK; } diff --git a/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginCallback.cs b/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginCallback.cs index c703349c..b12816ee 100644 --- a/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginCallback.cs +++ b/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginCallback.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using AudibleApi; using AudibleUtilities; @@ -13,43 +14,43 @@ namespace LibationAvalonia.Dialogs.Login _account = Dinah.Core.ArgumentValidator.EnsureNotNull(account, nameof(account)); } - public string Get2faCode() + public async Task Get2faCodeAsync() { var dialog = new _2faCodeDialog(); - if (ShowDialog(dialog)) + if (await ShowDialog(dialog)) return dialog.Code; return null; } - public string GetCaptchaAnswer(byte[] captchaImage) + public async Task GetCaptchaAnswerAsync(byte[] captchaImage) { var dialog = new CaptchaDialog(captchaImage); - if (ShowDialog(dialog)) + if (await ShowDialog(dialog)) return dialog.Answer; 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); - if (ShowDialog(dialog)) + if (await ShowDialog(dialog)) return (dialog.SelectedName, dialog.SelectedValue); return (null, null); } - public (string email, string password) GetLogin() + public async Task<(string email, string password)> GetLoginAsync() { var dialog = new LoginCallbackDialog(_account); - if (ShowDialog(dialog)) + if (await ShowDialog(dialog)) return (_account.AccountId, dialog.Password); return (null, null); } - public void ShowApprovalNeeded() + public async Task ShowApprovalNeededAsync() { var dialog = new ApprovalNeededDialog(); - ShowDialog(dialog); + await ShowDialog(dialog); } } } \ No newline at end of file diff --git a/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginChoiceEager.cs b/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginChoiceEager.cs index 4ab3afb9..4203e36f 100644 --- a/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginChoiceEager.cs +++ b/Source/LibationAvalonia/Dialogs/Login/AvaloniaLoginChoiceEager.cs @@ -20,11 +20,11 @@ namespace LibationAvalonia.Dialogs.Login LoginCallback = new AvaloniaLoginCallback(_account); } - public ChoiceOut Start(ChoiceIn choiceIn) + public async Task StartAsync(ChoiceIn choiceIn) { var dialog = new LoginChoiceEagerDialog(_account); - if (!ShowDialog(dialog)) + if (!await ShowDialog(dialog)) return null; @@ -33,15 +33,16 @@ namespace LibationAvalonia.Dialogs.Login case LoginMethod.Api: return ChoiceOut.WithApi(dialog.Account.AccountId, dialog.Password); case LoginMethod.External: - { - var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl); - return ShowDialog(externalDialog) - ? ChoiceOut.External(externalDialog.ResponseUrl) - : null; - } + { + var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl); + return await ShowDialog(externalDialog) + ? ChoiceOut.External(externalDialog.ResponseUrl) + : null; + } default: throw new Exception($"Unknown {nameof(LoginMethod)} value"); } } + } } diff --git a/Source/LibationAvalonia/Dialogs/Login/LoginExternalDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/Login/LoginExternalDialog.axaml.cs index 7021772a..85f1cb1a 100644 --- a/Source/LibationAvalonia/Dialogs/Login/LoginExternalDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/Login/LoginExternalDialog.axaml.cs @@ -51,7 +51,7 @@ namespace LibationAvalonia.Dialogs.Login Serilog.Log.Logger.Information("Submit button clicked: {@DebugInfo}", new { ResponseUrl }); if (!Uri.TryCreate(ResponseUrl, UriKind.Absolute, out var result)) { - MessageBox.Show("Invalid response URL"); + await MessageBox.Show("Invalid response URL"); return; } await base.SaveAndCloseAsync(); diff --git a/Source/LibationAvalonia/Dialogs/Login/MfaDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/Login/MfaDialog.axaml.cs index ccbd129e..ebb542eb 100644 --- a/Source/LibationAvalonia/Dialogs/Login/MfaDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/Login/MfaDialog.axaml.cs @@ -82,7 +82,7 @@ namespace LibationAvalonia.Dialogs.Login }); 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; } diff --git a/Source/LibationAvalonia/Dialogs/MessageBoxAlertAdminDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/MessageBoxAlertAdminDialog.axaml.cs index b2524f0e..b4d85f27 100644 --- a/Source/LibationAvalonia/Dialogs/MessageBoxAlertAdminDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/MessageBoxAlertAdminDialog.axaml.cs @@ -28,7 +28,7 @@ namespace LibationAvalonia.Dialogs 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"; try @@ -37,11 +37,11 @@ namespace LibationAvalonia.Dialogs } 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 = ""; try @@ -56,7 +56,7 @@ namespace LibationAvalonia.Dialogs } 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); } } diff --git a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs index a961bdc1..6527aafa 100644 --- a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs @@ -33,10 +33,10 @@ namespace LibationAvalonia.Dialogs protected override async Task SaveAndCloseAsync() { - if (!settingsDisp.SaveSettings(config)) + if (!await settingsDisp.SaveSettingsAsync(config)) return; - MessageBox.VerboseLoggingWarning_ShowIfTrue(); + await MessageBox.VerboseLoggingWarning_ShowIfTrue(); await base.SaveAndCloseAsync(); } @@ -97,7 +97,7 @@ namespace LibationAvalonia.Dialogs internal interface ISettingsDisplay { void LoadSettings(Configuration config); - bool SaveSettings(Configuration config); + Task SaveSettingsAsync(Configuration config); } public class SettingsPages : ISettingsDisplay @@ -120,12 +120,12 @@ namespace LibationAvalonia.Dialogs AudioSettings = new(config); } - public bool SaveSettings(Configuration config) + public async Task SaveSettingsAsync(Configuration config) { - var result = ImportantSettings.SaveSettings(config); - result &= ImportSettings.SaveSettings(config); - result &= DownloadDecryptSettings.SaveSettings(config); - result &= AudioSettings.SaveSettings(config); + var result = await ImportantSettings.SaveSettingsAsync(config); + result &= await ImportSettings.SaveSettingsAsync(config); + result &= await DownloadDecryptSettings.SaveSettingsAsync(config); + result &= await AudioSettings.SaveSettingsAsync(config); return result; } @@ -146,13 +146,13 @@ namespace LibationAvalonia.Dialogs BetaOptIn = config.BetaOptIn; } - public bool SaveSettings(Configuration config) + public async Task SaveSettingsAsync(Configuration config) { #region validation 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; } @@ -204,14 +204,14 @@ namespace LibationAvalonia.Dialogs AutoDownloadEpisodes = config.AutoDownloadEpisodes; } - public bool SaveSettings(Configuration config) + public Task SaveSettingsAsync(Configuration config) { config.AutoScan = AutoScan; config.ShowImportedStats = ShowImportedStats; config.ImportEpisodes = ImportEpisodes; config.DownloadEpisodes = DownloadEpisodes; config.AutoDownloadEpisodes = AutoDownloadEpisodes; - return true; + return Task.FromResult(true); } public string AutoScanText { get; } = Configuration.GetDescription(nameof(Configuration.AutoScan)); @@ -259,25 +259,25 @@ namespace LibationAvalonia.Dialogs : Configuration.GetKnownDirectory(config.InProgress); } - public bool SaveSettings(Configuration config) + public async Task 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); // these 3 should do nothing. Configuration will only init these with a valid value. EditTemplateDialog ensures valid before returning 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; } 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; } 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; } @@ -405,7 +405,7 @@ namespace LibationAvalonia.Dialogs LameVBRQuality = config.LameVBRQuality; } - public bool SaveSettings(Configuration config) + public Task SaveSettingsAsync(Configuration config) { config.CreateCueSheet = CreateCueSheet; config.AllowLibationFixup = AllowLibationFixup; @@ -424,7 +424,7 @@ namespace LibationAvalonia.Dialogs config.LameBitrate = LameBitrate; config.LameVBRQuality = LameVBRQuality; - return true; + return Task.FromResult(true); } public string CreateCueSheetText { get; } = Configuration.GetDescription(nameof(Configuration.CreateCueSheet)); diff --git a/Source/LibationAvalonia/FormSaveExtension.cs b/Source/LibationAvalonia/FormSaveExtension.cs index 5464ec82..3b041e92 100644 --- a/Source/LibationAvalonia/FormSaveExtension.cs +++ b/Source/LibationAvalonia/FormSaveExtension.cs @@ -113,7 +113,7 @@ namespace LibationAvalonia public static void HideMinMaxBtns(this Window form) { - if (Design.IsDesignMode || App.PlatformID is not PlatformID.Win32NT) + if (Design.IsDesignMode || !App.IsWindows) return; var handle = form.PlatformImpl.Handle.Handle; var currentStyle = GetWindowLong(handle, GWL_STYLE); diff --git a/Source/LibationAvalonia/LibationAvalonia.csproj b/Source/LibationAvalonia/LibationAvalonia.csproj index 8b3f9e96..7546869a 100644 --- a/Source/LibationAvalonia/LibationAvalonia.csproj +++ b/Source/LibationAvalonia/LibationAvalonia.csproj @@ -10,6 +10,8 @@ libation.ico Libation + true + true false false @@ -81,8 +83,6 @@ - - @@ -144,4 +144,12 @@ + + + + + + + + \ No newline at end of file diff --git a/Source/LibationAvalonia/MessageBox.cs b/Source/LibationAvalonia/MessageBox.cs index 26de6e0f..0c7aa958 100644 --- a/Source/LibationAvalonia/MessageBox.cs +++ b/Source/LibationAvalonia/MessageBox.cs @@ -62,34 +62,34 @@ namespace LibationAvalonia public class MessageBox { - public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) + public static Task Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton 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 Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, bool saveAndRestorePosition = true) => ShowCoreAsync(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1, saveAndRestorePosition); -public static DialogResult Show(string text, string caption, MessageBoxButtons buttons) +public static Task Show(string text, string caption, MessageBoxButtons buttons) => ShowCoreAsync(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - public static DialogResult Show(string text, string caption) + public static Task Show(string text, string caption) => ShowCoreAsync(null, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - public static DialogResult Show(string text) + public static Task Show(string text) => 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 Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton 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 Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) => ShowCoreAsync(owner, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); - public static DialogResult Show(Window owner, string text, string caption, MessageBoxButtons buttons) + public static Task Show(Window owner, string text, string caption, MessageBoxButtons buttons) => ShowCoreAsync(owner, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - public static DialogResult Show(Window owner, string text, string caption) + public static Task Show(Window owner, string text, string caption) => ShowCoreAsync(owner, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - public static DialogResult Show(Window owner, string text) + public static Task Show(Window owner, string text) => 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 if (Serilog.Log.Logger.IsVerboseEnabled()) - Show(@" + await Show(@" Warning: verbose logging is enabled. This should be used for debugging only. It creates many @@ -102,7 +102,7 @@ Libation. ".Trim(), "Verbose logging enabled", MessageBoxButtons.OK, MessageBoxIcon.Warning); } - public static DialogResult ShowConfirmationDialog(Window owner, IEnumerable libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) + public static async Task ShowConfirmationDialog(Window owner, IEnumerable libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) { if (libraryBooks is null || !libraryBooks.Any()) return DialogResult.Cancel; @@ -117,7 +117,7 @@ Libation. = string.Format(format, $"{thisThese} {count} {bookBooks}") + $"\r\n\r\n{titlesAgg}"; - return ShowCoreAsync(owner, + return await ShowCoreAsync(owner, message, title, MessageBoxButtons.YesNo, @@ -132,7 +132,7 @@ Libation. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// Exception to log. - 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! if (System.Diagnostics.Debugger.IsAttached) @@ -146,14 +146,14 @@ Libation. 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 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) @@ -192,13 +192,13 @@ Libation. dialog.Width = dialog.MinWidth; return dialog; } - private static DialogResult DisplayWindow(Window toDisplay, Window owner) + private static async Task DisplayWindow(Window toDisplay, Window owner) { if (owner is null) { if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - return toDisplay.ShowDialogSynchronously(desktop.MainWindow); + return await toDisplay.ShowDialog(desktop.MainWindow); } else { @@ -212,7 +212,7 @@ Libation. }; window.Show(); - var result = toDisplay.ShowDialogSynchronously(window); + var result = await toDisplay.ShowDialog(window); window.Close(); return result; } @@ -220,7 +220,7 @@ Libation. } else { - return toDisplay.ShowDialogSynchronously(owner); + return await toDisplay.ShowDialog(owner); } } diff --git a/Source/LibationAvalonia/Program.cs b/Source/LibationAvalonia/Program.cs index 8410798f..f0208cfe 100644 --- a/Source/LibationAvalonia/Program.cs +++ b/Source/LibationAvalonia/Program.cs @@ -14,7 +14,7 @@ namespace LibationAvalonia { private static string EXE_DIR = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); - static async Task Main() + static void Main() { //***********************************************// // // @@ -30,6 +30,14 @@ namespace LibationAvalonia var classicLifetimeTask = Task.Run(() => new ClassicDesktopStyleApplicationLifetime()); var appBuilderTask = Task.Run(BuildAvaloniaApp); + if (App.IsWindows) + AppScaffolding.LibationScaffolding.SetReleaseIdentifier(AppScaffolding.ReleaseIdentifier.WindowsAvalonia); + else if (App.IsLinux) + AppScaffolding.LibationScaffolding.SetReleaseIdentifier(AppScaffolding.ReleaseIdentifier.LinuxAvalonia); + else if (App.IsMacOs) + AppScaffolding.LibationScaffolding.SetReleaseIdentifier(AppScaffolding.ReleaseIdentifier.MacOSAvalonia); + else return; + if (!App.SetupRequired) { @@ -39,9 +47,7 @@ namespace LibationAvalonia App.LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true)); } - - - (await appBuilderTask).SetupWithLifetime(await classicLifetimeTask); + (appBuilderTask.GetAwaiter().GetResult()).SetupWithLifetime(classicLifetimeTask.GetAwaiter().GetResult()); classicLifetimeTask.Result.Start(null); } diff --git a/Source/LibationAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml b/Source/LibationAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml index 4f12172b..a846a327 100644 --- a/Source/LibationAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml +++ b/Source/LibationAvalonia/Properties/PublishProfiles/LinuxProfile.pubxml @@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU - ..\bin-Avalonia\publish\linux-x64\ + ..\bin\Release\linux-chardonnay FileSystem net6.0 linux-x64 diff --git a/Source/LibationAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml b/Source/LibationAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml index 2fc8471a..5d1e98f9 100644 --- a/Source/LibationAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml +++ b/Source/LibationAvalonia/Properties/PublishProfiles/MacOSProfile.pubxml @@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU - ..\bin-Avalonia\publish\osx-x64\ + ..\bin\Release\macos-chardonnay FileSystem net6.0 osx-x64 diff --git a/Source/LibationAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml b/Source/LibationAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml index 34da8075..1490c0a5 100644 --- a/Source/LibationAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml +++ b/Source/LibationAvalonia/Properties/PublishProfiles/WindowsProfile.pubxml @@ -6,8 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU - - ..\bin\publish\win-avalonia-x64\ + ..\bin\Release\win-chardonnay FileSystem net6.0 win-x64 diff --git a/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs b/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs index c2b673a0..0acb338c 100644 --- a/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs +++ b/Source/LibationAvalonia/ViewModels/ProcessBookViewModel.cs @@ -152,7 +152,7 @@ namespace LibationAvalonia.ViewModels finally { if (Result == ProcessBookResult.None) - Result = showRetry(LibraryBook); + Result = await showRetry(LibraryBook); Status = Result switch { @@ -313,7 +313,7 @@ namespace LibationAvalonia.ViewModels #region Failure Handler - private ProcessBookResult showRetry(LibraryBook libraryBook) + private async Task showRetry(LibraryBook libraryBook) { 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 - 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) return ProcessBookResult.FailedAbort; diff --git a/Source/LibationAvalonia/ViewModels/ProductsDisplayViewModel.cs b/Source/LibationAvalonia/ViewModels/ProductsDisplayViewModel.cs index 26858ca4..41dad536 100644 --- a/Source/LibationAvalonia/ViewModels/ProductsDisplayViewModel.cs +++ b/Source/LibationAvalonia/ViewModels/ProductsDisplayViewModel.cs @@ -244,7 +244,7 @@ namespace LibationAvalonia.ViewModels return; var libraryBooks = selectedBooks.Select(rge => rge.LibraryBook).ToList(); - var result = MessageBox.ShowConfirmationDialog( + var result = await MessageBox.ShowConfirmationDialog( null, libraryBooks, $"Are you sure you want to remove {selectedBooks.Count} books from Libation's library?", @@ -317,7 +317,7 @@ namespace LibationAvalonia.ViewModels } catch (Exception ex) { - MessageBox.ShowAdminAlert( + await MessageBox.ShowAdminAlert( null, "Error scanning library. You may still manually select books to remove from Libation's library.", "Error scanning library", diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.Export.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.Export.axaml.cs index 0c2e925a..fa39ebc3 100644 --- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.Export.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.Export.axaml.cs @@ -41,11 +41,11 @@ namespace LibationAvalonia.Views 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) { - 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); } } } diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.Filter.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.Filter.axaml.cs index ea4ba592..e550abf2 100644 --- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.Filter.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.Filter.axaml.cs @@ -39,7 +39,7 @@ namespace LibationAvalonia.Views } 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 await performFilter(lastGoodFilter); diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.Liberate.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.Liberate.axaml.cs index 171f4c55..6aab470f 100644 --- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.Liberate.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.Liberate.axaml.cs @@ -40,7 +40,7 @@ namespace LibationAvalonia.Views 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." + "\r\nFor large libraries this will take a long time and will take up more disk space." + "\r\n\r\nContinue?" diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.ProcessQueue.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.ProcessQueue.axaml.cs index 71d77635..73151b2c 100644 --- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.ProcessQueue.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.ProcessQueue.axaml.cs @@ -15,7 +15,7 @@ namespace LibationAvalonia.Views SetQueueCollapseState(collapseState); } - public void ProductsDisplay_LiberateClicked(object sender, LibraryBook libraryBook) + public async void ProductsDisplay_LiberateClicked(object sender, LibraryBook libraryBook) { try { @@ -39,7 +39,7 @@ namespace LibationAvalonia.Views if (!App.GoToFile(filePath?.ShortPathName)) { var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}"; - MessageBox.Show($"File not found" + suffix); + await MessageBox.Show($"File not found" + suffix); } } } diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.ScanManual.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.ScanManual.axaml.cs index d42c983c..acd9602e 100644 --- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.ScanManual.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.ScanManual.axaml.cs @@ -26,7 +26,7 @@ namespace LibationAvalonia.Views 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); } @@ -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 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) { - MessageBox.ShowAdminAlert( + await MessageBox.ShowAdminAlert( this, "Error importing library. Please try again. If this still happens after 2 or 3 tries, stop and contact administrator", "Error importing library", diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.Settings.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.Settings.axaml.cs index d59ba480..1b707922 100644 --- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.Settings.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.Settings.axaml.cs @@ -8,11 +8,13 @@ namespace LibationAvalonia.Views { 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) - => MessageBox.Show($"Running Libation version {AppScaffolding.LibationScaffolding.BuildVersion}", $"Libation v{AppScaffolding.LibationScaffolding.BuildVersion}"); + public async void aboutToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) + => await MessageBox.Show($"Running Libation version {AppScaffolding.LibationScaffolding.BuildVersion}", $"Libation v{AppScaffolding.LibationScaffolding.BuildVersion}"); } } diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.VisibleBooks.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.VisibleBooks.axaml.cs index 18cc6068..b0fce463 100644 --- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.VisibleBooks.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.VisibleBooks.axaml.cs @@ -47,7 +47,7 @@ namespace LibationAvalonia.Views var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries(); - var confirmationResult = MessageBox.ShowConfirmationDialog( + var confirmationResult = await MessageBox.ShowConfirmationDialog( this, visibleLibraryBooks, "Are you sure you want to replace tags in {0}?", @@ -70,7 +70,7 @@ namespace LibationAvalonia.Views var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries(); - var confirmationResult = MessageBox.ShowConfirmationDialog( + var confirmationResult = await MessageBox.ShowConfirmationDialog( this, visibleLibraryBooks, "Are you sure you want to replace downloaded status in {0}?", @@ -88,7 +88,7 @@ namespace LibationAvalonia.Views { var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries(); - var confirmationResult = MessageBox.ShowConfirmationDialog( + var confirmationResult = await MessageBox.ShowConfirmationDialog( this, visibleLibraryBooks, "Are you sure you want to remove {0} from Libation's library?", diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs index 7f6cd23d..64d0dced 100644 --- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs @@ -9,6 +9,7 @@ using LibationFileManager; using DataLayer; using System.Collections.Generic; using System.Threading.Tasks; +using AppScaffolding; namespace LibationAvalonia.Views { @@ -53,7 +54,7 @@ namespace LibationAvalonia.Views this.LibraryLoaded += MainWindow_LibraryLoaded; LibraryCommands.LibrarySizeChanged += async (_, _) => await _viewModel.ProductsDisplay.DisplayBooks(DbContexts.GetLibrary_Flat_NoTracking(includeParents: true)); - Closing += (_,_) => this.SaveSizeAndLocation(Configuration.Instance); + Closing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance); } Opened += MainWindow_Opened; Closing += MainWindow_Closing; @@ -67,50 +68,72 @@ namespace LibationAvalonia.Views private async void MainWindow_Opened(object sender, EventArgs e) { #if !DEBUG - if (App.IsWindows) + //This is temporaty until we have a solution for linux/mac so that + //Libation doesn't download a zip every time it runs. + if (!App.IsWindows) + return; + + try { - try - { - await Task.Run(checkForAndDownloadUpdate); - } - catch(Exception ex) - { - Serilog.Log.Logger.Error(ex, "An error occured while checking for app updates."); + (string zipFile, UpgradeProperties upgradeProperties) = await Task.Run(() => downloadUpdate()); + + if (string.IsNullOrEmpty(zipFile) || !System.IO.File.Exists(zipFile)) return; + + 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) + return; + + if (App.IsWindows) + { + runWindowsUpgrader(zipFile); } + else if (App.IsLinux) + { + + } + else if (App.IsMacOs) + { + + } + } + catch (Exception ex) + { + Serilog.Log.Logger.Error(ex, "An error occured while checking for app updates."); + return; } #endif } - private async Task checkForAndDownloadUpdate() + private async Task<(string zipFile, UpgradeProperties release)> downloadUpdate() { - AppScaffolding.UpgradeProperties upgradeProperties; + UpgradeProperties upgradeProperties; try { - upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease(AppScaffolding.LibationScaffolding.ReleaseIdentifier.WindowsAvalonia); - + upgradeProperties = LibationScaffolding.GetLatestRelease(); if (upgradeProperties is null) - return; + return (null,null); } catch (Exception ex) { Serilog.Log.Logger.Error(ex, "Failed to check for update"); - return; + return (null, null); } if (upgradeProperties.ZipUrl is null) { Serilog.Log.Logger.Information("Download link for new version not found"); - return; + return (null, null); } //Silently download the update in the background, save it to a temp file. - var zipPath = System.IO.Path.GetTempFileName(); + var zipFile = System.IO.Path.GetTempFileName(); try { System.Net.Http.HttpClient cli = new(); - using (var fs = System.IO.File.OpenWrite(zipPath)) + using (var fs = System.IO.File.OpenWrite(zipFile)) { using (var dlStream = await cli.GetStreamAsync(new Uri(upgradeProperties.ZipUrl))) await dlStream.CopyToAsync(fs); @@ -119,18 +142,18 @@ namespace LibationAvalonia.Views catch (Exception ex) { Serilog.Log.Logger.Error(ex, "Failed to download the update: {pdate}", upgradeProperties.ZipUrl); - return; + return (null, null); } + return (zipFile, upgradeProperties); + } - var result = 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) - return; + private void runWindowsUpgrader(string zipFile) + { var thisExe = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; var thisDir = System.IO.Path.GetDirectoryName(thisExe); - var args = $"--input {zipPath} --output {thisDir} --executable {thisExe}"; + var args = $"--input {zipFile} --output {thisDir} --executable {thisExe}"; var zipExtractor = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "ZipExtractor.exe"); @@ -147,7 +170,7 @@ namespace LibationAvalonia.Views }; System.Diagnostics.Process.Start(psi); - Environment.Exit(0); + Environment.Exit(0); } public void ProductsDisplay_Initialized1(object sender, EventArgs e) diff --git a/Source/LibationCli/LibationCli.csproj b/Source/LibationCli/LibationCli.csproj index 9aa6ab5f..ef5b0954 100644 --- a/Source/LibationCli/LibationCli.csproj +++ b/Source/LibationCli/LibationCli.csproj @@ -1,27 +1,26 @@  - - Exe - net6.0 - true - win-x64 - false - false - True - + + Exe + net6.0 + true + false + false + True + - - - en;es - + en;es + - - - ..\bin\Debug - embedded - + + ..\bin\Debug + embedded + - - ..\bin\Release - embedded - + + ..\bin\Release + embedded + - - - + + + - - - - - + + + + + + + + + + + + diff --git a/Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml b/Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml index 4f12172b..a846a327 100644 --- a/Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml +++ b/Source/LibationCli/Properties/PublishProfiles/LinuxProfile.pubxml @@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU - ..\bin-Avalonia\publish\linux-x64\ + ..\bin\Release\linux-chardonnay FileSystem net6.0 linux-x64 diff --git a/Source/LibationCli/Properties/PublishProfiles/MacOSProfile.pubxml b/Source/LibationCli/Properties/PublishProfiles/MacOSProfile.pubxml index 2fc8471a..5d1e98f9 100644 --- a/Source/LibationCli/Properties/PublishProfiles/MacOSProfile.pubxml +++ b/Source/LibationCli/Properties/PublishProfiles/MacOSProfile.pubxml @@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU - ..\bin-Avalonia\publish\osx-x64\ + ..\bin\Release\macos-chardonnay FileSystem net6.0 osx-x64 diff --git a/Source/LibationCli/Properties/PublishProfiles/WindowsProfile.pubxml b/Source/LibationCli/Properties/PublishProfiles/WindowsProfile.pubxml index 257cfc2b..1490c0a5 100644 --- a/Source/LibationCli/Properties/PublishProfiles/WindowsProfile.pubxml +++ b/Source/LibationCli/Properties/PublishProfiles/WindowsProfile.pubxml @@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU - ..\bin\publish\ + ..\bin\Release\win-chardonnay FileSystem net6.0 win-x64 diff --git a/Source/LibationWinForms/Dialogs/Login/WinformLoginCallback.cs b/Source/LibationWinForms/Dialogs/Login/WinformLoginCallback.cs index 2a1b273e..4728b8ea 100644 --- a/Source/LibationWinForms/Dialogs/Login/WinformLoginCallback.cs +++ b/Source/LibationWinForms/Dialogs/Login/WinformLoginCallback.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using AudibleApi; using AudibleUtilities; using LibationWinForms.Dialogs.Login; @@ -14,42 +15,43 @@ namespace LibationWinForms.Login _account = Dinah.Core.ArgumentValidator.EnsureNotNull(account, nameof(account)); } - public string Get2faCode() + public Task Get2faCodeAsync() { using var dialog = new _2faCodeDialog(); if (ShowDialog(dialog)) - return dialog.Code; - return null; + return Task.FromResult(dialog.Code); + return Task.FromResult(null); } - public string GetCaptchaAnswer(byte[] captchaImage) + public Task GetCaptchaAnswerAsync(byte[] captchaImage) { using var dialog = new CaptchaDialog(captchaImage); if (ShowDialog(dialog)) - return dialog.Answer; - return null; + return Task.FromResult(dialog.Answer); + return Task.FromResult(null); } - public (string name, string value) GetMfaChoice(MfaConfig mfaConfig) + public Task<(string name, string value)> GetMfaChoiceAsync(MfaConfig mfaConfig) { using var dialog = new MfaDialog(mfaConfig); if (ShowDialog(dialog)) - return (dialog.SelectedName, dialog.SelectedValue); - return (null, null); + return Task.FromResult((dialog.SelectedName, dialog.SelectedValue)); + 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); if (ShowDialog(dialog)) - return (dialog.Email, dialog.Password); - return (null, null); + return Task.FromResult((dialog.Email, dialog.Password)); + return Task.FromResult<(string, string)>((null, null)); } - public void ShowApprovalNeeded() + public Task ShowApprovalNeededAsync() { using var dialog = new ApprovalNeededDialog(); ShowDialog(dialog); + return Task.CompletedTask; } } } \ No newline at end of file diff --git a/Source/LibationWinForms/Dialogs/Login/WinformLoginChoiceEager.cs b/Source/LibationWinForms/Dialogs/Login/WinformLoginChoiceEager.cs index 00d77c98..0543d80f 100644 --- a/Source/LibationWinForms/Dialogs/Login/WinformLoginChoiceEager.cs +++ b/Source/LibationWinForms/Dialogs/Login/WinformLoginChoiceEager.cs @@ -21,7 +21,7 @@ namespace LibationWinForms.Login LoginCallback = new WinformLoginCallback(_account); } - public ChoiceOut Start(ChoiceIn choiceIn) + public Task StartAsync(ChoiceIn choiceIn) { using var dialog = new LoginChoiceEagerDialog(_account); @@ -31,13 +31,14 @@ namespace LibationWinForms.Login switch (dialog.LoginMethod) { case LoginMethod.Api: - return ChoiceOut.WithApi(dialog.Email, dialog.Password); + return Task.FromResult(ChoiceOut.WithApi(dialog.Email, dialog.Password)); case LoginMethod.External: { using var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl); - return ShowDialog(externalDialog) - ? ChoiceOut.External(externalDialog.ResponseUrl) - : null; + return Task.FromResult( + ShowDialog(externalDialog) + ? ChoiceOut.External(externalDialog.ResponseUrl) + : null); } default: throw new Exception($"Unknown {nameof(LoginMethod)} value"); diff --git a/Source/LibationWinForms/LibationWinForms.csproj b/Source/LibationWinForms/LibationWinForms.csproj index dcd48471..bfbcf0da 100644 --- a/Source/LibationWinForms/LibationWinForms.csproj +++ b/Source/LibationWinForms/LibationWinForms.csproj @@ -1,91 +1,99 @@  - - WinExe - net6.0-windows - true - libation.ico - Libation - - true - win-x64 - false - false - + + WinExe + net6.0-windows + true + libation.ico + Libation - - + true + win-x64 + false + false + + true + + - - - en;es - + en;es + - - ..\bin\Debug - embedded - + + ..\bin\Debug + embedded + - - ..\bin\Release - embedded - - - - - - + + ..\bin\Release + embedded + - - - - + + + - - - - - - - - Form1.cs - - - - - - SettingsDialog.cs - - - - - Form1.cs - - + + + + + + + + + + + + Form1.cs - - - True - True - Resources.resx - - + + + SettingsDialog.cs + + + + + Form1.cs + + + + + Form1.cs + + - - - ResXFileCodeGenerator - Resources.Designer.cs - - + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + \ No newline at end of file diff --git a/Source/LibationWinForms/Program.cs b/Source/LibationWinForms/Program.cs index 36b174a2..53833005 100644 --- a/Source/LibationWinForms/Program.cs +++ b/Source/LibationWinForms/Program.cs @@ -30,6 +30,8 @@ namespace LibationWinForms ApplicationConfiguration.Initialize(); + AppScaffolding.LibationScaffolding.SetReleaseIdentifier(AppScaffolding.ReleaseIdentifier.WindowsClassic); + //***********************************************// // // // do not use Configuration before this line // @@ -170,7 +172,7 @@ namespace LibationWinForms try { - upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease(AppScaffolding.LibationScaffolding.ReleaseIdentifier.WindowsClassic); + upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease(); if (upgradeProperties is null) return; }