From ac4c1687259ef9da5e540b3ce17e8aea6c268d7d Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Mon, 4 Aug 2025 17:29:13 -0600 Subject: [PATCH] Allow Libation to start with an invalid Books directory - Configuration.LibationSettingsAreValid is true if Books property exists and is any non-null, non-empty string. - If LibationSettingsAreValid is false, Libation will prompt user to set up Libation. - When the main window is shown, Libation checks if the books directory exists, and if it doesn't, user is notified and prompted to change their setting - When a user tries to liberate or convert a book, Books directory is validated and user notified if it does not exist. --- Source/LibationAvalonia/App.axaml.cs | 23 ++++---- .../Dialogs/SettingsDialog.axaml.cs | 19 ++++++- .../Settings/ImportantSettingsVM.cs | 10 ++-- .../Views/MainWindow.axaml.cs | 14 +++++ Source/LibationCli/Options/ConvertOptions.cs | 13 ++++- Source/LibationCli/Options/LiberateOptions.cs | 12 ++++- .../LibationFileManager/AudibleFileStorage.cs | 31 +++++++---- .../Configuration.PersistentSettings.cs | 8 +-- Source/LibationFileManager/Configuration.cs | 52 +++++++++++-------- .../ProcessQueue/ProcessQueueViewModel.cs | 36 +++++++++++++ .../Dialogs/SettingsDialog.Important.cs | 31 +++++++---- .../Dialogs/SettingsDialog.cs | 2 +- Source/LibationWinForms/Form1.Settings.cs | 24 ++++++++- Source/LibationWinForms/Program.cs | 14 +++-- 14 files changed, 217 insertions(+), 72 deletions(-) diff --git a/Source/LibationAvalonia/App.axaml.cs b/Source/LibationAvalonia/App.axaml.cs index 9c89e841..bbff098b 100644 --- a/Source/LibationAvalonia/App.axaml.cs +++ b/Source/LibationAvalonia/App.axaml.cs @@ -111,7 +111,7 @@ namespace LibationAvalonia if (setupDialog.Config.LibationSettingsAreValid) { string? theme = setupDialog.SelectedTheme.Content as string; - + setupDialog.Config.SetString(theme, nameof(ThemeVariant)); await RunMigrationsAsync(setupDialog.Config); @@ -120,7 +120,10 @@ namespace LibationAvalonia ShowMainWindow(desktop); } else - await CancelInstallation(); + { + e.Cancel = true; + await CancelInstallation(setupDialog); + } } else if (setupDialog.IsReturningUser) { @@ -128,7 +131,8 @@ namespace LibationAvalonia } else { - await CancelInstallation(); + e.Cancel = true; + await CancelInstallation(setupDialog); return; } @@ -139,11 +143,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 { - await MessageBox.ShowAdminAlert(null, body, title, ex); + await MessageBox.ShowAdminAlert(setupDialog, body, title, ex); } catch { - await MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error); + await MessageBox.Show(setupDialog, $"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error); } return; } @@ -190,6 +194,7 @@ namespace LibationAvalonia { // path did not result in valid settings var continueResult = await MessageBox.Show( + libationFilesDialog, $"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, @@ -207,18 +212,18 @@ namespace LibationAvalonia ShowMainWindow(desktop); } else - await CancelInstallation(); + await CancelInstallation(libationFilesDialog); } else - await CancelInstallation(); + await CancelInstallation(libationFilesDialog); } libationFilesDialog.Close(); } - static async Task CancelInstallation() + static async Task CancelInstallation(Window window) { - await MessageBox.Show("Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning); + await MessageBox.Show(window, "Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning); Environment.Exit(0); } diff --git a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs index 5155973e..910d2f87 100644 --- a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs @@ -1,7 +1,9 @@ using Avalonia.Controls; +using FileManager; using LibationAvalonia.ViewModels.Settings; using LibationFileManager; using LibationUiBase.Forms; +using System; using System.Threading.Tasks; namespace LibationAvalonia.Dialogs @@ -39,6 +41,21 @@ namespace LibationAvalonia.Dialogs } public async void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e) - => await SaveAndCloseAsync(); + { + LongPath lonNewBooks = settingsDisp.ImportantSettings.GetBooksDirectory(); + if (!System.IO.Directory.Exists(lonNewBooks)) + { + try + { + System.IO.Directory.CreateDirectory(lonNewBooks); + } + catch (Exception ex) + { + await MessageBox.Show(this, $"Error creating Books Location:\n\n{ex.Message}", "Error creating directory", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + } + await SaveAndCloseAsync(); + } } } diff --git a/Source/LibationAvalonia/ViewModels/Settings/ImportantSettingsVM.cs b/Source/LibationAvalonia/ViewModels/Settings/ImportantSettingsVM.cs index d74710c8..28544c9f 100644 --- a/Source/LibationAvalonia/ViewModels/Settings/ImportantSettingsVM.cs +++ b/Source/LibationAvalonia/ViewModels/Settings/ImportantSettingsVM.cs @@ -35,11 +35,8 @@ namespace LibationAvalonia.ViewModels.Settings } public void SaveSettings(Configuration config) - { - LongPath lonNewBooks = Configuration.GetKnownDirectory(BooksDirectory) is Configuration.KnownDirectories.None ? BooksDirectory : System.IO.Path.Combine(BooksDirectory, "Books"); - if (!System.IO.Directory.Exists(lonNewBooks)) - System.IO.Directory.CreateDirectory(lonNewBooks); - config.Books = lonNewBooks; + { + config.Books = GetBooksDirectory(); config.SavePodcastsToParentFolder = SavePodcastsToParentFolder; config.OverwriteExisting = OverwriteExisting; config.CreationTime = CreationTime.Value; @@ -47,6 +44,9 @@ namespace LibationAvalonia.ViewModels.Settings config.LogLevel = LoggingLevel; } + public LongPath GetBooksDirectory() + => Configuration.GetKnownDirectory(BooksDirectory) is Configuration.KnownDirectories.None ? BooksDirectory : System.IO.Path.Combine(BooksDirectory, "Books"); + private static float scaleFactorToLinearRange(float scaleFactor) => float.Round(100 * MathF.Log2(scaleFactor)); private static float linearRangeToScaleFactor(float value) diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow.axaml.cs index f36d8cf7..f1bb1a28 100644 --- a/Source/LibationAvalonia/Views/MainWindow.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow.axaml.cs @@ -135,6 +135,20 @@ namespace LibationAvalonia.Views private async void MainWindow_Opened(object sender, EventArgs e) { + if (AudibleFileStorage.BooksDirectory is null) + { + var result = await MessageBox.Show( + this, + "Please set a valid Books location in the settings dialog.", + "Books Directory Not Set", + MessageBoxButtons.OKCancel, + MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + + if (result is DialogResult.OK) + await new SettingsDialog().ShowDialog(this); + } + if (Configuration.Instance.FirstLaunch) { var result = await MessageBox.Show(this, "Would you like a guided tour to get started?", "Libation Walkthrough", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); diff --git a/Source/LibationCli/Options/ConvertOptions.cs b/Source/LibationCli/Options/ConvertOptions.cs index b20f0152..c20bab91 100644 --- a/Source/LibationCli/Options/ConvertOptions.cs +++ b/Source/LibationCli/Options/ConvertOptions.cs @@ -1,4 +1,6 @@ using CommandLine; +using LibationFileManager; +using System; using System.Threading.Tasks; namespace LibationCli @@ -6,6 +8,15 @@ namespace LibationCli [Verb("convert", HelpText = "Convert mp4 to mp3.")] public class ConvertOptions : ProcessableOptionsBase { - protected override Task ProcessAsync() => RunAsync(CreateProcessable()); + protected override Task ProcessAsync() + { + if (AudibleFileStorage.BooksDirectory is null) + { + Console.Error.WriteLine("Error: Books directory is not set. Please configure the 'Books' setting in Settings.json."); + return Task.CompletedTask; + } + + return RunAsync(CreateProcessable()); + } } } diff --git a/Source/LibationCli/Options/LiberateOptions.cs b/Source/LibationCli/Options/LiberateOptions.cs index ab1a8e78..9f8fdf63 100644 --- a/Source/LibationCli/Options/LiberateOptions.cs +++ b/Source/LibationCli/Options/LiberateOptions.cs @@ -1,6 +1,8 @@ using CommandLine; using DataLayer; using FileLiberator; +using LibationFileManager; +using System; using System.Threading.Tasks; namespace LibationCli @@ -13,9 +15,17 @@ namespace LibationCli public bool PdfOnly { get; set; } protected override Task ProcessAsync() - => PdfOnly + { + if (AudibleFileStorage.BooksDirectory is null) + { + Console.Error.WriteLine("Error: Books directory is not set. Please configure the 'Books' setting in Settings.json."); + return Task.CompletedTask; + } + + return PdfOnly ? RunAsync(CreateProcessable()) : RunAsync(CreateBackupBook()); + } private static Processable CreateBackupBook() { diff --git a/Source/LibationFileManager/AudibleFileStorage.cs b/Source/LibationFileManager/AudibleFileStorage.cs index 1a1c8b73..a298777e 100644 --- a/Source/LibationFileManager/AudibleFileStorage.cs +++ b/Source/LibationFileManager/AudibleFileStorage.cs @@ -45,13 +45,24 @@ namespace LibationFileManager public static AudioFileStorage Audio { get; } = new AudioFileStorage(); - public static LongPath BooksDirectory + /// + /// The fully-qualified Books durectory path if the directory exists, otherwise null. + /// + public static LongPath? BooksDirectory { get { if (string.IsNullOrWhiteSpace(Configuration.Instance.Books)) - Configuration.Instance.Books = Configuration.DefaultBooksDirectory; - return Directory.CreateDirectory(Configuration.Instance.Books).FullName; + return null; + try + { + return Directory.CreateDirectory(Configuration.Instance.Books)?.FullName; + } + catch (Exception ex) + { + Serilog.Log.Error(ex, "Error creating Books directory: {@BooksDirectory}", Configuration.Instance.Books); + return null; + } } } #endregion @@ -129,8 +140,9 @@ namespace LibationFileManager protected override LongPath? GetFilePathCustom(string productId) => GetFilePathsCustom(productId).FirstOrDefault(); - private static BackgroundFileSystem newBookDirectoryFiles() - => new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories); + private static BackgroundFileSystem? newBookDirectoryFiles() + => BooksDirectory is LongPath books ? new BackgroundFileSystem(books, "*.*", SearchOption.AllDirectories) + : null; protected override List GetFilePathsCustom(string productId) { @@ -140,6 +152,7 @@ namespace LibationFileManager BookDirectoryFiles = newBookDirectoryFiles(); var regex = GetBookSearchRegex(productId); + var diskFiles = BookDirectoryFiles?.FindFiles(regex) ?? []; //Find all extant files matching the productId //using both the file system and the file path cache @@ -148,17 +161,17 @@ namespace LibationFileManager .GetFiles(productId) .Where(c => c.fileType == FileType.Audio && File.Exists(c.path)) .Select(c => c.path) - .Union(BookDirectoryFiles.FindFiles(regex)) + .Union(diskFiles) .ToList(); } public void Refresh() { - if (BookDirectoryFiles is null) + if (BookDirectoryFiles is null && BooksDirectory is not null) lock (bookDirectoryFilesLocker) BookDirectoryFiles = newBookDirectoryFiles(); - else - BookDirectoryFiles?.RefreshFiles(); + + BookDirectoryFiles?.RefreshFiles(); } public LongPath? GetPath(string productId) => GetFilePath(productId); diff --git a/Source/LibationFileManager/Configuration.PersistentSettings.cs b/Source/LibationFileManager/Configuration.PersistentSettings.cs index be4a5a7e..b0e99649 100644 --- a/Source/LibationFileManager/Configuration.PersistentSettings.cs +++ b/Source/LibationFileManager/Configuration.PersistentSettings.cs @@ -36,12 +36,12 @@ namespace LibationFileManager [return: NotNullIfNotNull(nameof(defaultValue))] public T? GetNonString(T defaultValue, [CallerMemberName] string propertyName = "") - => Settings.GetNonString(propertyName, defaultValue); + => Settings is null ? default : Settings.GetNonString(propertyName, defaultValue); [return: NotNullIfNotNull(nameof(defaultValue))] public string? GetString(string? defaultValue = null, [CallerMemberName] string propertyName = "") - => Settings.GetString(propertyName, defaultValue); + => Settings?.GetString(propertyName, defaultValue); public object? GetObject([CallerMemberName] string propertyName = "") => Settings.GetObject(propertyName); @@ -132,13 +132,13 @@ namespace LibationFileManager /// True if the Books directory can be written to with 255 unicode character filenames /// Does not persist. Check and set this value at runtime and whenever Books is changed. /// - public bool BooksCanWrite255UnicodeChars => m_BooksCanWrite255UnicodeChars ??= FileSystemTest.CanWrite255UnicodeChars(Books); + public bool BooksCanWrite255UnicodeChars => m_BooksCanWrite255UnicodeChars ??= FileSystemTest.CanWrite255UnicodeChars(AudibleFileStorage.BooksDirectory); /// /// True if the Books directory can be written to with filenames containing characters invalid on Windows (:, *, ?, <, >, |) /// Always false on Windows platforms. /// Does not persist. Check and set this value at runtime and whenever Books is changed. /// - public bool BooksCanWriteWindowsInvalidChars => !IsWindows && (m_BooksCanWriteWindowsInvalidChars ??= FileSystemTest.CanWriteWindowsInvalidChars(Books)); + public bool BooksCanWriteWindowsInvalidChars => !IsWindows && (m_BooksCanWriteWindowsInvalidChars ??= FileSystemTest.CanWriteWindowsInvalidChars(AudibleFileStorage.BooksDirectory)); [Description("Overwrite existing files if they already exist?")] public bool OverwriteExisting { get => GetNonString(defaultValue: false); set => SetNonString(value); } diff --git a/Source/LibationFileManager/Configuration.cs b/Source/LibationFileManager/Configuration.cs index 4eb01822..1a500e02 100644 --- a/Source/LibationFileManager/Configuration.cs +++ b/Source/LibationFileManager/Configuration.cs @@ -3,48 +3,58 @@ using System.IO; using System.Linq; using Dinah.Core; using FileManager; +using Newtonsoft.Json.Linq; #nullable enable namespace LibationFileManager { public partial class Configuration : PropertyChangeFilter { + /// + /// Returns true if exists and the property has a non-null, non-empty value. + /// Does not verify the existence of the directory. + /// public bool LibationSettingsAreValid => SettingsFileIsValid(SettingsFilePath); + /// + /// Returns true if exists and the property has a non-null, non-empty value. + /// Does not verify the existence of the directory. + /// + /// File path to the settings JSON file public static bool SettingsFileIsValid(string settingsFile) { if (!Directory.Exists(Path.GetDirectoryName(settingsFile)) || !File.Exists(settingsFile)) return false; - var pDic = new PersistentDictionary(settingsFile, isReadOnly: false); - - if (pDic.GetString(nameof(Books)) is not string booksDir) - return false; - - if (!Directory.Exists(booksDir)) + try { - if (Path.GetDirectoryName(settingsFile) is not string dir) - throw new DirectoryNotFoundException(settingsFile); - - //"Books" is not null, so setup has already been run. - //Since Books can't be found, try to create it - //and then revert to the default books directory - foreach (string d in new string[] { booksDir, DefaultBooksDirectory }) + var settingsJson = JObject.Parse(File.ReadAllText(settingsFile)); + return !string.IsNullOrWhiteSpace(settingsJson[nameof(Books)]?.Value()); + } + catch (Exception ex) + { + Serilog.Log.Logger.Error(ex, "Failed to load settings file: {@SettingsFile}", settingsFile); + try { + Serilog.Log.Logger.Information("Deleting invalid settings file: {@SettingsFile}", settingsFile); + FileUtility.SaferDelete(settingsFile); + Serilog.Log.Logger.Information("Creating a new, empty setting file: {@SettingsFile}", settingsFile); try { - Directory.CreateDirectory(d); - - pDic.SetString(nameof(Books), d); - - return Directory.Exists(d); + File.WriteAllText(settingsFile, "{}"); + } + catch (Exception createEx) + { + Serilog.Log.Logger.Error(createEx, "Failed to create new settings file: {@SettingsFile}", settingsFile); } - catch { /* Do Nothing */ } } + catch (Exception deleteEx) + { + Serilog.Log.Logger.Error(deleteEx, "Failed to delete the invalid settings file: {@SettingsFile}", settingsFile); + } + return false; } - - return true; } #region singleton stuff diff --git a/Source/LibationUiBase/ProcessQueue/ProcessQueueViewModel.cs b/Source/LibationUiBase/ProcessQueue/ProcessQueueViewModel.cs index b9c1619a..9a3472d8 100644 --- a/Source/LibationUiBase/ProcessQueue/ProcessQueueViewModel.cs +++ b/Source/LibationUiBase/ProcessQueue/ProcessQueueViewModel.cs @@ -1,5 +1,6 @@ using ApplicationServices; using DataLayer; +using LibationFileManager; using LibationUiBase.Forms; using System; using System.Collections.Generic; @@ -95,6 +96,9 @@ public class ProcessQueueViewModel : ReactiveObject public bool QueueDownloadPdf(IList libraryBooks) { + if (!IsBooksDirectoryValid()) + return false; + var needsPdf = libraryBooks.Where(lb => lb.NeedsPdfDownload()).ToArray(); if (needsPdf.Length > 0) { @@ -107,6 +111,9 @@ public class ProcessQueueViewModel : ReactiveObject public bool QueueConvertToMp3(IList libraryBooks) { + if (!IsBooksDirectoryValid()) + return false; + //Only Queue Liberated books for conversion. This isn't a perfect filter, but it's better than nothing. var preLiberated = libraryBooks.Where(lb => !lb.AbsentFromLastScan && lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated && lb.Book.ContentType is DataLayer.ContentType.Product).ToArray(); if (preLiberated.Length > 0) @@ -122,6 +129,9 @@ public class ProcessQueueViewModel : ReactiveObject public bool QueueDownloadDecrypt(IList libraryBooks) { + if (!IsBooksDirectoryValid()) + return false; + if (libraryBooks.Count == 1) { var item = libraryBooks[0]; @@ -157,6 +167,32 @@ public class ProcessQueueViewModel : ReactiveObject return false; } + private bool IsBooksDirectoryValid() + { + if (string.IsNullOrWhiteSpace(Configuration.Instance.Books)) + { + Serilog.Log.Logger.Error("Books location is not set in configuration."); + MessageBoxBase.Show( + "Please choose a \"Books location\" folder in the Settings menu.", + "Books Directory Not Set", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return false; + } + else if (AudibleFileStorage.BooksDirectory is null) + { + Serilog.Log.Logger.Error("Failed to create books directory: {@booksDir}", Configuration.Instance.Books); + MessageBoxBase.Show( + $"Libation was unable to create the \"Books location\" folder at:\n{Configuration.Instance.Books}\n\nPlease change the Books location in the settings menu.", + "Failed to Create Books Directory", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return false; + } + + return true; + } + private bool IsBookInQueue(LibraryBook libraryBook) => Queue.FirstOrDefault(b => b?.LibraryBook?.Book?.AudibleProductId == libraryBook.Book.AudibleProductId) is not ProcessBookViewModel entry ? false : entry.Status is ProcessBookStatus.Cancelled or ProcessBookStatus.Failed ? !Queue.RemoveCompleted(entry) diff --git a/Source/LibationWinForms/Dialogs/SettingsDialog.Important.cs b/Source/LibationWinForms/Dialogs/SettingsDialog.Important.cs index 29c235be..54f137ee 100644 --- a/Source/LibationWinForms/Dialogs/SettingsDialog.Important.cs +++ b/Source/LibationWinForms/Dialogs/SettingsDialog.Important.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Windows.Forms; +#nullable enable namespace LibationWinForms.Dialogs { public partial class SettingsDialog @@ -55,7 +56,7 @@ namespace LibationWinForms.Dialogs }, Configuration.KnownDirectories.UserProfile, "Books"); - booksSelectControl.SelectDirectory(config.Books.PathWithoutPrefix); + booksSelectControl.SelectDirectory(config.Books?.PathWithoutPrefix ?? ""); saveEpisodesToSeriesFolderCbox.Checked = config.SavePodcastsToParentFolder; overwriteExistingCbox.Checked = config.OverwriteExisting; @@ -63,7 +64,7 @@ namespace LibationWinForms.Dialogs gridFontScaleFactorTbar.Value = scaleFactorToLinearRange(config.GridFontScaleFactor); } - private void Save_Important(Configuration config) + private bool Save_Important(Configuration config) { var newBooks = booksSelectControl.SelectedDirectory; @@ -73,19 +74,29 @@ namespace LibationWinForms.Dialogs if (string.IsNullOrWhiteSpace(newBooks)) { validationError("Cannot set Books Location to blank", "Location is blank"); - return; + return false; + } + LongPath lonNewBooks = newBooks; + if (!Directory.Exists(lonNewBooks)) + { + try + { + Directory.CreateDirectory(lonNewBooks); + } + catch (Exception ex) + { + validationError($"Error creating Books Location:\r\n{ex.Message}", "Error creating directory"); + return false; + } } #endregion - LongPath lonNewBooks = newBooks; - if (!Directory.Exists(lonNewBooks)) - Directory.CreateDirectory(lonNewBooks); config.Books = newBooks; { var logLevelOld = config.LogLevel; - var logLevelNew = (Serilog.Events.LogEventLevel)loggingLevelCb.SelectedItem; + var logLevelNew = (loggingLevelCb.SelectedItem as Serilog.Events.LogEventLevel?) ?? Serilog.Events.LogEventLevel.Information; config.LogLevel = logLevelNew; @@ -97,9 +108,9 @@ namespace LibationWinForms.Dialogs config.SavePodcastsToParentFolder = saveEpisodesToSeriesFolderCbox.Checked; config.OverwriteExisting = overwriteExistingCbox.Checked; - - config.CreationTime = ((EnumDisplay)creationTimeCb.SelectedItem).Value; - config.LastWriteTime = ((EnumDisplay)lastWriteTimeCb.SelectedItem).Value; + config.CreationTime = (creationTimeCb.SelectedItem as EnumDisplay)?.Value ?? Configuration.DateTimeSource.File; + config.LastWriteTime = (lastWriteTimeCb.SelectedItem as EnumDisplay)?.Value ?? Configuration.DateTimeSource.File; + return true; } private static int scaleFactorToLinearRange(float scaleFactor) diff --git a/Source/LibationWinForms/Dialogs/SettingsDialog.cs b/Source/LibationWinForms/Dialogs/SettingsDialog.cs index 555e651f..2c028bf5 100644 --- a/Source/LibationWinForms/Dialogs/SettingsDialog.cs +++ b/Source/LibationWinForms/Dialogs/SettingsDialog.cs @@ -43,7 +43,7 @@ namespace LibationWinForms.Dialogs private void saveBtn_Click(object sender, EventArgs e) { - Save_Important(config); + if (!Save_Important(config)) return; Save_ImportLibrary(config); Save_DownloadDecrypt(config); Save_AudioSettings(config); diff --git a/Source/LibationWinForms/Form1.Settings.cs b/Source/LibationWinForms/Form1.Settings.cs index 07ce09c0..735ff308 100644 --- a/Source/LibationWinForms/Form1.Settings.cs +++ b/Source/LibationWinForms/Form1.Settings.cs @@ -6,9 +6,29 @@ namespace LibationWinForms { public partial class Form1 { - private void Configure_Settings() { } + private void Configure_Settings() + { + Shown += FormShown_Settings; + } - private void accountsToolStripMenuItem_Click(object sender, EventArgs e) => new AccountsDialog().ShowDialog(); + private void FormShown_Settings(object sender, EventArgs e) + { + if (LibationFileManager.AudibleFileStorage.BooksDirectory is null) + { + var result = MessageBox.Show( + this, + "Please set a valid Books location in the settings dialog.", + "Books Directory Not Set", + MessageBoxButtons.OKCancel, + MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + + if (result is DialogResult.OK) + new SettingsDialog().ShowDialog(this); + } + } + + private void accountsToolStripMenuItem_Click(object sender, EventArgs e) => new AccountsDialog().ShowDialog(); private void basicSettingsToolStripMenuItem_Click(object sender, EventArgs e) => new SettingsDialog().ShowDialog(); diff --git a/Source/LibationWinForms/Program.cs b/Source/LibationWinForms/Program.cs index ba1416f0..61eb28f0 100644 --- a/Source/LibationWinForms/Program.cs +++ b/Source/LibationWinForms/Program.cs @@ -148,7 +148,10 @@ namespace LibationWinForms } if (setupDialog.IsNewUser) + { Configuration.SetLibationFiles(defaultLibationFilesDir); + config.Books = Configuration.DefaultBooksDirectory; + } else if (setupDialog.IsReturningUser) { var libationFilesDialog = new LibationFilesDialog(); @@ -175,16 +178,11 @@ namespace LibationWinForms CancelInstallation(); return; } + config.Books = Configuration.DefaultBooksDirectory; } - // INIT DEFAULT SETTINGS - // if 'new user' was clicked, or if 'returning user' chose new install: show basic settings dialog - config.Books ??= Configuration.DefaultBooksDirectory; - - if (config.LibationSettingsAreValid) - return; - - CancelInstallation(); + if (!config.LibationSettingsAreValid) + CancelInstallation(); } /// migrations which require Forms or are long-running