diff --git a/Source/AppScaffolding/AppScaffolding.csproj b/Source/AppScaffolding/AppScaffolding.csproj
index c4ee9183..ad40a990 100644
--- a/Source/AppScaffolding/AppScaffolding.csproj
+++ b/Source/AppScaffolding/AppScaffolding.csproj
@@ -3,7 +3,7 @@
net6.0-windows
- 7.4.0.1
+ 7.5.0.1
diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs
index 8c181354..773a3567 100644
--- a/Source/ApplicationServices/LibraryCommands.cs
+++ b/Source/ApplicationServices/LibraryCommands.cs
@@ -313,7 +313,7 @@ namespace ApplicationServices
// must be here instead of in db layer due to AaxcExists
public static LiberatedStatus Liberated_Status(Book book)
- => book.Audio_Exists ? book.UserDefinedItem.BookStatus
+ => book.Audio_Exists() ? book.UserDefinedItem.BookStatus
: AudibleFileStorage.AaxcExists(book.AudibleProductId) ? LiberatedStatus.PartialDownload
: LiberatedStatus.NotLiberated;
@@ -340,7 +340,7 @@ namespace ApplicationServices
var boolResults = libraryBooks
.AsParallel()
- .Where(lb => lb.Book.HasPdf)
+ .Where(lb => lb.Book.HasPdf())
.Select(lb => Pdf_Status(lb.Book))
.ToList();
var pdfsDownloaded = boolResults.Count(r => r == LiberatedStatus.Liberated);
diff --git a/Source/ApplicationServices/LibraryExporter.cs b/Source/ApplicationServices/LibraryExporter.cs
index 4508d7ed..3f948e66 100644
--- a/Source/ApplicationServices/LibraryExporter.cs
+++ b/Source/ApplicationServices/LibraryExporter.cs
@@ -111,13 +111,13 @@ namespace ApplicationServices
AudibleProductId = a.Book.AudibleProductId,
Locale = a.Book.Locale,
Title = a.Book.Title,
- AuthorNames = a.Book.AuthorNames,
- NarratorNames = a.Book.NarratorNames,
+ AuthorNames = a.Book.AuthorNames(),
+ NarratorNames = a.Book.NarratorNames(),
LengthInMinutes = a.Book.LengthInMinutes,
Description = a.Book.Description,
Publisher = a.Book.Publisher,
- HasPdf = a.Book.HasPdf,
- SeriesNames = a.Book.SeriesNames,
+ HasPdf = a.Book.HasPdf(),
+ SeriesNames = a.Book.SeriesNames(),
SeriesOrder = a.Book.SeriesLink.Any() ? a.Book.SeriesLink?.Select(sl => $"{sl.Order} : {sl.Series.Name}").Aggregate((a, b) => $"{a}, {b}") : "",
CommunityRatingOverall = a.Book.Rating?.OverallRating,
CommunityRatingPerformance = a.Book.Rating?.PerformanceRating,
@@ -125,7 +125,7 @@ namespace ApplicationServices
PictureId = a.Book.PictureId,
IsAbridged = a.Book.IsAbridged,
DatePublished = a.Book.DatePublished,
- CategoriesNames = a.Book.CategoriesNames.Any() ? a.Book.CategoriesNames.Aggregate((a, b) => $"{a}, {b}") : "",
+ CategoriesNames = a.Book.CategoriesNames().Any() ? a.Book.CategoriesNames().Aggregate((a, b) => $"{a}, {b}") : "",
MyRatingOverall = a.Book.UserDefinedItem.Rating.OverallRating,
MyRatingPerformance = a.Book.UserDefinedItem.Rating.PerformanceRating,
MyRatingStory = a.Book.UserDefinedItem.Rating.StoryRating,
diff --git a/Source/DataLayer/EfClasses/Book.cs b/Source/DataLayer/EfClasses/Book.cs
index 63d3e7c3..804df40a 100644
--- a/Source/DataLayer/EfClasses/Book.cs
+++ b/Source/DataLayer/EfClasses/Book.cs
@@ -43,27 +43,10 @@ namespace DataLayer
// non-null. use "empty pattern"
internal int CategoryId { get; private set; }
public Category Category { get; private set; }
- public string[] CategoriesNames
- => Category is null ? new string[0]
- : Category.ParentCategory is null ? new[] { Category.Name }
- : new[] { Category.ParentCategory.Name, Category.Name };
- public string[] CategoriesIds
- => Category is null ? null
- : Category.ParentCategory is null ? new[] { Category.AudibleCategoryId }
- : new[] { Category.ParentCategory.AudibleCategoryId, Category.AudibleCategoryId };
-
- public string TitleSortable => Formatters.GetSortName(Title);
- public string SeriesSortable => Formatters.GetSortName(SeriesNames);
// is owned, not optional 1:1
public UserDefinedItem UserDefinedItem { get; private set; }
- // UserDefinedItem convenience properties
- /// True if IsLiberated or Error. False if NotLiberated
- public bool Audio_Exists => UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated;
- /// True if exists and IsLiberated. Else false
- public bool PDF_Exists => UserDefinedItem.PdfStatus == LiberatedStatus.Liberated;
-
// is owned, not optional 1:1
/// The product's aggregate community rating
public Rating Rating { get; private set; } = new Rating(0, 0, 0);
@@ -125,11 +108,7 @@ namespace DataLayer
.ToList();
public IEnumerable Authors => getContributions(Role.Author).Select(bc => bc.Contributor).ToList();
- public string AuthorNames => string.Join(", ", Authors.Select(a => a.Name));
-
public IEnumerable Narrators => getContributions(Role.Narrator).Select(bc => bc.Contributor).ToList();
- public string NarratorNames => string.Join(", ", Narrators.Select(n => n.Name));
-
public string Publisher => getContributions(Role.Publisher).SingleOrDefault()?.Contributor.Name;
public void ReplaceAuthors(IEnumerable authors, DbContext context = null)
@@ -185,30 +164,6 @@ namespace DataLayer
#region series
private HashSet _seriesLink;
public IEnumerable SeriesLink => _seriesLink?.ToList();
- public string SeriesNames
- {
- get
- {
- if (_seriesLink is null)
- return "";
-
- // first: alphabetical by name
- var withNames = _seriesLink
- .Where(s => !string.IsNullOrWhiteSpace(s.Series.Name))
- .Select(s => s.Series.Name)
- .OrderBy(a => a)
- .ToList();
- // then un-named are alpha by series id
- var nullNames = _seriesLink
- .Where(s => string.IsNullOrWhiteSpace(s.Series.Name))
- .Select(s => s.Series.AudibleSeriesId)
- .OrderBy(a => a)
- .ToList();
-
- var all = withNames.Union(nullNames).ToList();
- return string.Join(", ", all);
- }
- }
public void UpsertSeries(Series series, string order, DbContext context = null)
{
@@ -230,7 +185,6 @@ namespace DataLayer
#region supplements
private HashSet _supplements;
public IEnumerable Supplements => _supplements?.ToList();
- public bool HasPdf => Supplements.Any();
public void AddSupplementDownloadUrl(string url)
{
diff --git a/Source/DataLayer/EfClasses/Rating.cs b/Source/DataLayer/EfClasses/Rating.cs
index 25ee3e28..761633be 100644
--- a/Source/DataLayer/EfClasses/Rating.cs
+++ b/Source/DataLayer/EfClasses/Rating.cs
@@ -38,41 +38,6 @@ namespace DataLayer
yield return StoryRating;
}
- public float FirstScore
- => OverallRating > 0 ? OverallRating
- : PerformanceRating > 0 ? PerformanceRating
- : StoryRating;
-
- /// character: ★
- const char STAR = '\u2605';
- /// character: ½
- const char HALF = '\u00BD';
- string getStars(float score)
- {
- var fullStars = (int)Math.Floor(score);
-
- var starString = "".PadLeft(fullStars, STAR);
-
- if (score - fullStars == 0.5f)
- starString += HALF;
-
- return starString;
- }
-
- public string ToStarString()
- {
- var items = new List();
-
- if (OverallRating > 0)
- items.Add($"Overall: {getStars(OverallRating)}");
- if (PerformanceRating > 0)
- items.Add($"Perform: {getStars(PerformanceRating)}");
- if (StoryRating > 0)
- items.Add($"Story: {getStars(StoryRating)}");
-
- return string.Join("\r\n", items);
- }
-
public override string ToString() => $"Overall={OverallRating} Perf={PerformanceRating} Story={StoryRating}";
}
}
diff --git a/Source/DataLayer/EntityExtensions.cs b/Source/DataLayer/EntityExtensions.cs
new file mode 100644
index 00000000..ef18a232
--- /dev/null
+++ b/Source/DataLayer/EntityExtensions.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DataLayer
+{
+ public static class EntityExtensions
+ {
+ public static string TitleSortable(this Book book) => Formatters.GetSortName(book.Title);
+
+ public static string AuthorNames(this Book book) => string.Join(", ", book.Authors.Select(a => a.Name));
+ public static string NarratorNames(this Book book) => string.Join(", ", book.Narrators.Select(n => n.Name));
+
+ /// True if IsLiberated or Error. False if NotLiberated
+ public static bool Audio_Exists(this Book book) => book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated;
+ /// True if exists and IsLiberated. Else false
+ public static bool PDF_Exists(this Book book) => book.UserDefinedItem.PdfStatus == LiberatedStatus.Liberated;
+
+ public static string SeriesSortable(this Book book) => Formatters.GetSortName(book.SeriesNames());
+ public static bool HasPdf(this Book book) => book.Supplements.Any();
+ public static string SeriesNames(this Book book)
+ {
+ if (book.SeriesLink is null)
+ return "";
+
+ // first: alphabetical by name
+ var withNames = book.SeriesLink
+ .Where(s => !string.IsNullOrWhiteSpace(s.Series.Name))
+ .Select(s => s.Series.Name)
+ .OrderBy(a => a)
+ .ToList();
+ // then un-named are alpha by series id
+ var nullNames = book.SeriesLink
+ .Where(s => string.IsNullOrWhiteSpace(s.Series.Name))
+ .Select(s => s.Series.AudibleSeriesId)
+ .OrderBy(a => a)
+ .ToList();
+
+ var all = withNames.Union(nullNames).ToList();
+ return string.Join(", ", all);
+ }
+ public static string[] CategoriesNames(this Book book)
+ => book.Category is null ? new string[0]
+ : book.Category.ParentCategory is null ? new[] { book.Category.Name }
+ : new[] { book.Category.ParentCategory.Name, book.Category.Name };
+ public static string[] CategoriesIds(this Book book)
+ => book.Category is null ? null
+ : book.Category.ParentCategory is null ? new[] { book.Category.AudibleCategoryId }
+ : new[] { book.Category.ParentCategory.AudibleCategoryId, book.Category.AudibleCategoryId };
+
+ public static string AggregateTitles(this IEnumerable libraryBooks, int max = 5)
+ {
+ if (libraryBooks is null || !libraryBooks.Any())
+ return "";
+
+ max = Math.Max(max, 1);
+
+ var titles = libraryBooks.Select(lb => "- " + lb.Book.Title).ToList();
+ var titlesAgg = titles.Take(max).Aggregate((a, b) => $"{a}\r\n{b}");
+ if (titles.Count == max + 1)
+ titlesAgg += $"\r\n\r\nand 1 other";
+ else if (titles.Count > max + 1)
+ titlesAgg += $"\r\n\r\nand {titles.Count - max } others";
+ return titlesAgg;
+ }
+
+ public static float FirstScore(this Rating rating)
+ => rating.OverallRating > 0 ? rating.OverallRating
+ : rating.PerformanceRating > 0 ? rating.PerformanceRating
+ : rating.StoryRating;
+ public static string ToStarString(this Rating rating)
+ {
+ var items = new List();
+
+ if (rating.OverallRating > 0)
+ items.Add($"Overall: {getStars(rating.OverallRating)}");
+ if (rating.PerformanceRating > 0)
+ items.Add($"Perform: {getStars(rating.PerformanceRating)}");
+ if (rating.StoryRating > 0)
+ items.Add($"Story: {getStars(rating.StoryRating)}");
+
+ return string.Join("\r\n", items);
+ }
+ /// character: ★
+ const char STAR = '\u2605';
+ /// character: ½
+ const char HALF = '\u00BD';
+ private static string getStars(float score)
+ {
+ var fullStars = (int)Math.Floor(score);
+
+ var starString = new string(STAR, fullStars);
+
+ if (score - fullStars >= 0.25f)
+ starString += HALF;
+
+ return starString;
+ }
+ }
+}
diff --git a/Source/FileLiberator/DownloadDecryptBook.cs b/Source/FileLiberator/DownloadDecryptBook.cs
index 7a9136eb..ef54d81d 100644
--- a/Source/FileLiberator/DownloadDecryptBook.cs
+++ b/Source/FileLiberator/DownloadDecryptBook.cs
@@ -18,7 +18,7 @@ namespace FileLiberator
public override string Name => "Download & Decrypt";
private AudiobookDownloadBase abDownloader;
- public override bool Validate(LibraryBook libraryBook) => !libraryBook.Book.Audio_Exists;
+ public override bool Validate(LibraryBook libraryBook) => !libraryBook.Book.Audio_Exists();
public override void Cancel() => abDownloader?.Cancel();
@@ -43,7 +43,7 @@ namespace FileLiberator
try
{
- if (libraryBook.Book.Audio_Exists)
+ if (libraryBook.Book.Audio_Exists())
return new StatusHandler { "Cannot find decrypt. Final audio file already exists" };
bool success = false;
@@ -120,7 +120,7 @@ namespace FileLiberator
: new AaxcDownloadSingleConverter(outFileName, cacheDir, audiobookDlLic);
if (config.AllowLibationFixup)
- converter.RetrievedMetadata += (_, tags) => tags.Generes = string.Join(", ", libraryBook.Book.CategoriesNames);
+ converter.RetrievedMetadata += (_, tags) => tags.Generes = string.Join(", ", libraryBook.Book.CategoriesNames());
abDownloader = converter;
}
diff --git a/Source/FileLiberator/DownloadPdf.cs b/Source/FileLiberator/DownloadPdf.cs
index 2ebd155a..5bc61f7c 100644
--- a/Source/FileLiberator/DownloadPdf.cs
+++ b/Source/FileLiberator/DownloadPdf.cs
@@ -17,7 +17,7 @@ namespace FileLiberator
public override string Name => "Download Pdf";
public override bool Validate(LibraryBook libraryBook)
=> !string.IsNullOrWhiteSpace(getdownloadUrl(libraryBook))
- && !libraryBook.Book.PDF_Exists;
+ && !libraryBook.Book.PDF_Exists();
public override async Task ProcessAsync(LibraryBook libraryBook)
{
diff --git a/Source/LibationSearchEngine/SearchEngine.cs b/Source/LibationSearchEngine/SearchEngine.cs
index ac365a35..f10ea71c 100644
--- a/Source/LibationSearchEngine/SearchEngine.cs
+++ b/Source/LibationSearchEngine/SearchEngine.cs
@@ -30,8 +30,14 @@ namespace LibationSearchEngine
// the workaround which allows displaying all books when query is empty
public const string ALL_QUERY = "*:*";
- #region index rules
- private static ReadOnlyDictionary> idIndexRules { get; }
+ #region index rules
+ // common fields used in the "all" default search field
+ public const string ALL_AUDIBLE_PRODUCT_ID = nameof(Book.AudibleProductId);
+ public const string ALL_TITLE = nameof(Book.Title);
+ public const string ALL_AUTHOR_NAMES = "AuthorNames";
+ public const string ALL_NARRATOR_NAMES = "NarratorNames";
+
+ private static ReadOnlyDictionary> idIndexRules { get; }
= new ReadOnlyDictionary>(
new Dictionary>
{
@@ -50,15 +56,15 @@ namespace LibationSearchEngine
[nameof(Book.DatePublished)] = lb => lb.Book.DatePublished?.ToLuceneString(),
[nameof(Book.Title)] = lb => lb.Book.Title,
- [nameof(Book.AuthorNames)] = lb => lb.Book.AuthorNames,
- ["Author"] = lb => lb.Book.AuthorNames,
- ["Authors"] = lb => lb.Book.AuthorNames,
- [nameof(Book.NarratorNames)] = lb => lb.Book.NarratorNames,
- ["Narrator"] = lb => lb.Book.NarratorNames,
- ["Narrators"] = lb => lb.Book.NarratorNames,
+ [ALL_AUTHOR_NAMES] = lb => lb.Book.AuthorNames(),
+ ["Author"] = lb => lb.Book.AuthorNames(),
+ ["Authors"] = lb => lb.Book.AuthorNames(),
+ [ALL_NARRATOR_NAMES] = lb => lb.Book.NarratorNames(),
+ ["Narrator"] = lb => lb.Book.NarratorNames(),
+ ["Narrators"] = lb => lb.Book.NarratorNames(),
[nameof(Book.Publisher)] = lb => lb.Book.Publisher,
- [nameof(Book.SeriesNames)] = lb => string.Join(
+ ["SeriesNames"] = lb => string.Join(
", ",
lb.Book.SeriesLink
.Where(s => !string.IsNullOrWhiteSpace(s.Series.Name))
@@ -70,11 +76,11 @@ namespace LibationSearchEngine
.Select(s => s.Series.AudibleSeriesId)),
["SeriesId"] = lb => string.Join(", ", lb.Book.SeriesLink.Select(s => s.Series.AudibleSeriesId)),
- [nameof(Book.CategoriesNames)] = lb => lb.Book.CategoriesIds is null ? null : string.Join(", ", lb.Book.CategoriesIds),
- [nameof(Book.Category)] = lb => lb.Book.CategoriesIds is null ? null : string.Join(", ", lb.Book.CategoriesIds),
- ["Categories"] = lb => lb.Book.CategoriesIds is null ? null : string.Join(", ", lb.Book.CategoriesIds),
- ["CategoriesId"] = lb => lb.Book.CategoriesIds is null ? null : string.Join(", ", lb.Book.CategoriesIds),
- ["CategoryId"] = lb => lb.Book.CategoriesIds is null ? null : string.Join(", ", lb.Book.CategoriesIds),
+ ["CategoriesNames"] = lb => lb.Book.CategoriesIds() is null ? null : string.Join(", ", lb.Book.CategoriesIds()),
+ [nameof(Book.Category)] = lb => lb.Book.CategoriesIds() is null ? null : string.Join(", ", lb.Book.CategoriesIds()),
+ ["Categories"] = lb => lb.Book.CategoriesIds() is null ? null : string.Join(", ", lb.Book.CategoriesIds()),
+ ["CategoriesId"] = lb => lb.Book.CategoriesIds() is null ? null : string.Join(", ", lb.Book.CategoriesIds()),
+ ["CategoryId"] = lb => lb.Book.CategoriesIds() is null ? null : string.Join(", ", lb.Book.CategoriesIds()),
[TAGS.FirstCharToUpper()] = lb => lb.Book.UserDefinedItem.Tags,
@@ -107,14 +113,14 @@ namespace LibationSearchEngine
= new ReadOnlyDictionary>(
new Dictionary>
{
- ["HasDownloads"] = lb => lb.Book.HasPdf,
- ["HasDownload"] = lb => lb.Book.HasPdf,
- ["Downloads"] = lb => lb.Book.HasPdf,
- ["Download"] = lb => lb.Book.HasPdf,
- ["HasPDFs"] = lb => lb.Book.HasPdf,
- ["HasPDF"] = lb => lb.Book.HasPdf,
- ["PDFs"] = lb => lb.Book.HasPdf,
- ["PDF"] = lb => lb.Book.HasPdf,
+ ["HasDownloads"] = lb => lb.Book.HasPdf(),
+ ["HasDownload"] = lb => lb.Book.HasPdf(),
+ ["Downloads"] = lb => lb.Book.HasPdf(),
+ ["Download"] = lb => lb.Book.HasPdf(),
+ ["HasPDFs"] = lb => lb.Book.HasPdf(),
+ ["HasPDF"] = lb => lb.Book.HasPdf(),
+ ["PDFs"] = lb => lb.Book.HasPdf(),
+ ["PDF"] = lb => lb.Book.HasPdf(),
["IsRated"] = lb => lb.Book.UserDefinedItem.Rating.OverallRating > 0f,
["Rated"] = lb => lb.Book.UserDefinedItem.Rating.OverallRating > 0f,
@@ -151,10 +157,10 @@ namespace LibationSearchEngine
private static IEnumerable> allFieldIndexRules { get; }
= new List>
{
- idIndexRules[nameof(Book.AudibleProductId)],
- stringIndexRules[nameof(Book.Title)],
- stringIndexRules[nameof(Book.AuthorNames)],
- stringIndexRules[nameof(Book.NarratorNames)]
+ idIndexRules[ALL_AUDIBLE_PRODUCT_ID],
+ stringIndexRules[ALL_TITLE],
+ stringIndexRules[ALL_AUTHOR_NAMES],
+ stringIndexRules[ALL_NARRATOR_NAMES]
};
#endregion
diff --git a/Source/LibationWinForms/BookLiberation/AudioDecodeForm.cs b/Source/LibationWinForms/BookLiberation/AudioDecodeForm.cs
index 56775e8e..73d43562 100644
--- a/Source/LibationWinForms/BookLiberation/AudioDecodeForm.cs
+++ b/Source/LibationWinForms/BookLiberation/AudioDecodeForm.cs
@@ -26,8 +26,8 @@ namespace LibationWinForms.BookLiberation
//Set default values from library
AudioDecodable_TitleDiscovered(sender, libraryBook.Book.Title);
- AudioDecodable_AuthorsDiscovered(sender, libraryBook.Book.AuthorNames);
- AudioDecodable_NarratorsDiscovered(sender, libraryBook.Book.NarratorNames);
+ AudioDecodable_AuthorsDiscovered(sender, libraryBook.Book.AuthorNames());
+ AudioDecodable_NarratorsDiscovered(sender, libraryBook.Book.NarratorNames());
AudioDecodable_CoverImageDiscovered(sender,
PictureStorage.GetPicture(
new PictureDefinition(
diff --git a/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs b/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs
index 78c7d4c4..38a185c3 100644
--- a/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs
+++ b/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs
@@ -241,8 +241,8 @@ namespace LibationWinForms.BookLiberation
details =
$@" Title: {libraryBook.Book.Title}
ID: {libraryBook.Book.AudibleProductId}
- Author: {trunc(libraryBook.Book.AuthorNames)}
- Narr: {trunc(libraryBook.Book.NarratorNames)}";
+ Author: {trunc(libraryBook.Book.AuthorNames())}
+ Narr: {trunc(libraryBook.Book.NarratorNames())}";
}
catch
{
diff --git a/Source/LibationWinForms/Dialogs/AccountsDialog.cs b/Source/LibationWinForms/Dialogs/AccountsDialog.cs
index afcbbf79..7670c0dd 100644
--- a/Source/LibationWinForms/Dialogs/AccountsDialog.cs
+++ b/Source/LibationWinForms/Dialogs/AccountsDialog.cs
@@ -128,7 +128,7 @@ namespace LibationWinForms.Dialogs
}
catch (Exception ex)
{
- MessageBoxAlertAdmin.Show("Error attempting to save accounts", "Error saving accounts", ex);
+ MessageBoxLib.ShowAdminAlert("Error attempting to save accounts", "Error saving accounts", ex);
}
}
diff --git a/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs b/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs
index 89184b00..fdbc7ac7 100644
--- a/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs
+++ b/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs
@@ -46,15 +46,16 @@ namespace LibationWinForms.Dialogs
var t = @$"
Title: {Book.Title}
-Author(s): {Book.AuthorNames}
-Narrator(s): {Book.NarratorNames}
+Author(s): {Book.AuthorNames()}
+Narrator(s): {Book.NarratorNames()}
Length: {(Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min")}
-Category: {string.Join(" > ", Book.CategoriesNames)}
+Category: {string.Join(" > ", Book.CategoriesNames())}
Purchase Date: {_libraryBook.DateAdded.ToString("d")}
".Trim();
- if (!string.IsNullOrWhiteSpace(Book.SeriesNames))
- t += $"\r\nSeries: {Book.SeriesNames}";
+ var seriesNames = Book.SeriesNames();
+ if (!string.IsNullOrWhiteSpace(seriesNames))
+ t += $"\r\nSeries: {seriesNames}";
var bookRating = Book.Rating?.ToStarString();
if (!string.IsNullOrWhiteSpace(bookRating))
diff --git a/Source/LibationWinForms/Dialogs/EditTemplateDialog.cs b/Source/LibationWinForms/Dialogs/EditTemplateDialog.cs
index 734a49d4..693072f7 100644
--- a/Source/LibationWinForms/Dialogs/EditTemplateDialog.cs
+++ b/Source/LibationWinForms/Dialogs/EditTemplateDialog.cs
@@ -46,7 +46,7 @@ namespace LibationWinForms.Dialogs
if (template is null)
{
- MessageBoxAlertAdmin.Show($"Programming error. {nameof(EditTemplateDialog)} was not created correctly", "Edit template error", new NullReferenceException($"{nameof(template)} is null"));
+ MessageBoxLib.ShowAdminAlert($"Programming error. {nameof(EditTemplateDialog)} was not created correctly", "Edit template error", new NullReferenceException($"{nameof(template)} is null"));
return;
}
diff --git a/Source/LibationWinForms/Dialogs/RemoveBooksDialog.cs b/Source/LibationWinForms/Dialogs/RemoveBooksDialog.cs
index 1f7e18d9..2dac8bd9 100644
--- a/Source/LibationWinForms/Dialogs/RemoveBooksDialog.cs
+++ b/Source/LibationWinForms/Dialogs/RemoveBooksDialog.cs
@@ -77,7 +77,7 @@ namespace LibationWinForms.Dialogs
}
catch (Exception ex)
{
- MessageBoxAlertAdmin.Show(
+ MessageBoxLib.ShowAdminAlert(
"Error scanning library. You may still manually select books to remove from Libation's library.",
"Error scanning library",
ex);
@@ -95,34 +95,22 @@ namespace LibationWinForms.Dialogs
if (selectedBooks.Count == 0)
return;
- var titles = selectedBooks.Select(rge => "- " + rge.Title).ToList();
- var titlesAgg = titles.Take(5).Aggregate((a, b) => $"{a}\r\n{b}");
- if (titles.Count == 6)
- titlesAgg += $"\r\n\r\nand 1 other";
- else if (titles.Count > 6)
- titlesAgg += $"\r\n\r\nand {titles.Count - 5} others";
+ var libraryBooks = selectedBooks.Select(rge => rge.LibraryBook).ToList();
+ var result = MessageBoxLib.ShowConfirmationDialog(
+ libraryBooks,
+ $"Are you sure you want to remove {0} from Libation's library?",
+ "Remove books from Libation?");
- string thisThese = selectedBooks.Count > 1 ? "these" : "this";
- string bookBooks = selectedBooks.Count > 1 ? "books" : "book";
+ if (result != DialogResult.Yes)
+ return;
- var result = MessageBox.Show(
- this,
- $"Are you sure you want to remove {thisThese} {selectedBooks.Count} {bookBooks} from Libation's library?\r\n\r\n{titlesAgg}",
- "Remove books from Libation?",
- MessageBoxButtons.YesNo,
- MessageBoxIcon.Question,
- MessageBoxDefaultButton.Button1);
+ var idsToRemove = libraryBooks.Select(lb => lb.Book.AudibleProductId).ToList();
+ var removeLibraryBooks = await LibraryCommands.RemoveBooksAsync(idsToRemove);
- if (result == DialogResult.Yes)
- {
- var idsToRemove = selectedBooks.Select(rge => rge.AudibleProductId).ToList();
- var removeLibraryBooks = await LibraryCommands.RemoveBooksAsync(idsToRemove);
+ foreach (var rEntry in selectedBooks)
+ _removableGridEntries.Remove(rEntry);
- foreach (var rEntry in selectedBooks)
- _removableGridEntries.Remove(rEntry);
-
- UpdateSelection();
- }
+ UpdateSelection();
}
private void UpdateSelection()
diff --git a/Source/LibationWinForms/Dialogs/SettingsDialog.cs b/Source/LibationWinForms/Dialogs/SettingsDialog.cs
index 0741a0f3..cc84ecc2 100644
--- a/Source/LibationWinForms/Dialogs/SettingsDialog.cs
+++ b/Source/LibationWinForms/Dialogs/SettingsDialog.cs
@@ -181,7 +181,7 @@ namespace LibationWinForms.Dialogs
// only warn if changed during this time. don't want to warn every time user happens to change settings while level is verbose
if (logLevelOld != logLevelNew)
- MessageBoxVerboseLoggingWarning.ShowIfTrue();
+ MessageBoxLib.VerboseLoggingWarning_ShowIfTrue();
}
config.AllowLibationFixup = allowLibationFixupCbox.Checked;
diff --git a/Source/LibationWinForms/MessageBoxAlertAdmin.cs b/Source/LibationWinForms/MessageBoxAlertAdmin.cs
deleted file mode 100644
index 3d68836f..00000000
--- a/Source/LibationWinForms/MessageBoxAlertAdmin.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-using LibationWinForms.Dialogs;
-
-namespace LibationWinForms
-{
- public static class MessageBoxAlertAdmin
- {
- ///
- /// Logs error. Displays a message box dialog with specified text and caption.
- ///
- /// The text to display in the message box.
- /// The text to display in the title bar of the message box.
- /// Exception to log
- /// One of the System.Windows.Forms.DialogResult values.
- public static System.Windows.Forms.DialogResult Show(string text, string caption, Exception exception)
- {
- try
- {
- Serilog.Log.Logger.Error(exception, "Alert admin error: {@DebugText}", new { text, caption });
- }
- catch { }
-
- using var form = new MessageBoxAlertAdminDialog(text, caption, exception);
- return form.ShowDialog();
- }
- }
-}
diff --git a/Source/LibationWinForms/MessageBoxWarnIfVerboseLogging.cs b/Source/LibationWinForms/MessageBoxWarnIfVerboseLogging.cs
deleted file mode 100644
index 0f47ef3c..00000000
--- a/Source/LibationWinForms/MessageBoxWarnIfVerboseLogging.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using System.Linq;
-using Dinah.Core.Logging;
-using Serilog;
-using System.Windows.Forms;
-
-namespace LibationWinForms
-{
- public static class MessageBoxVerboseLoggingWarning
- {
- public static void ShowIfTrue()
- {
- // when turning on debug (and especially Verbose) to share logs, some privacy settings may not be obscured
- if (Log.Logger.IsVerboseEnabled())
- MessageBox.Show(@"
-Warning: verbose logging is enabled.
-
-This should be used for debugging only. It creates many
-more logs and debug files, neither of which are as
-strictly anonymous.
-
-When you are finished debugging, it's highly recommended
-to set your debug MinimumLevel to Information and restart
-Libation.
-".Trim(), "Verbose logging enabled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
- }
- }
-}
diff --git a/Source/LibationWinForms/Program.cs b/Source/LibationWinForms/Program.cs
index 30343ac0..f02df0ba 100644
--- a/Source/LibationWinForms/Program.cs
+++ b/Source/LibationWinForms/Program.cs
@@ -49,7 +49,7 @@ namespace LibationWinForms
// migrations which require Forms or are long-running
RunWindowsOnlyMigrations(config);
- MessageBoxVerboseLoggingWarning.ShowIfTrue();
+ MessageBoxLib.VerboseLoggingWarning_ShowIfTrue();
#if !DEBUG
checkForUpdate();
@@ -63,7 +63,7 @@ namespace LibationWinForms
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
{
- MessageBoxAlertAdmin.Show(body, title, ex);
+ MessageBoxLib.ShowAdminAlert(body, title, ex);
}
catch
{
@@ -178,7 +178,7 @@ namespace LibationWinForms
}
catch (Exception ex)
{
- MessageBoxAlertAdmin.Show("Error checking for update", "Error checking for update", ex);
+ MessageBoxLib.ShowAdminAlert("Error checking for update", "Error checking for update", ex);
return;
}
@@ -203,7 +203,7 @@ namespace LibationWinForms
}
catch (Exception ex)
{
- MessageBoxAlertAdmin.Show("Error downloading update", "Error downloading update", ex);
+ MessageBoxLib.ShowAdminAlert("Error downloading update", "Error downloading update", ex);
}
}
}
diff --git a/Source/LibationWinForms/grid/GridEntry.cs b/Source/LibationWinForms/grid/GridEntry.cs
index aee51d4c..0d20ef1f 100644
--- a/Source/LibationWinForms/grid/GridEntry.cs
+++ b/Source/LibationWinForms/grid/GridEntry.cs
@@ -128,14 +128,14 @@ namespace LibationWinForms
// Immutable properties
{
Title = Book.Title;
- Series = Book.SeriesNames;
+ Series = Book.SeriesNames();
Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min";
MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
PurchaseDate = libraryBook.DateAdded.ToString("d");
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
- Authors = Book.AuthorNames;
- Narrators = Book.NarratorNames;
- Category = string.Join(" > ", Book.CategoriesNames);
+ Authors = Book.AuthorNames();
+ Narrators = Book.NarratorNames();
+ Category = string.Join(" > ", Book.CategoriesNames());
Misc = GetMiscDisplay(libraryBook);
LongDescription = GetDescriptionDisplay(Book);
Description = TrimTextToWord(LongDescription, 62);
@@ -232,12 +232,12 @@ namespace LibationWinForms
///
private Dictionary> CreateMemberValueDictionary() => new()
{
- { nameof(Title), () => Book.TitleSortable },
- { nameof(Series), () => Book.SeriesSortable },
+ { nameof(Title), () => Book.TitleSortable() },
+ { nameof(Series), () => Book.SeriesSortable() },
{ nameof(Length), () => Book.LengthInMinutes },
- { nameof(MyRating), () => Book.UserDefinedItem.Rating.FirstScore },
+ { nameof(MyRating), () => Book.UserDefinedItem.Rating.FirstScore() },
{ nameof(PurchaseDate), () => LibraryBook.DateAdded },
- { nameof(ProductRating), () => Book.Rating.FirstScore },
+ { nameof(ProductRating), () => Book.Rating.FirstScore() },
{ nameof(Authors), () => Authors },
{ nameof(Narrators), () => Narrators },
{ nameof(Description), () => Description },
@@ -292,7 +292,7 @@ namespace LibationWinForms
details.Add($"Account: {locale} - {acct}");
- if (libraryBook.Book.HasPdf)
+ if (libraryBook.Book.HasPdf())
details.Add("Has PDF");
if (libraryBook.Book.IsAbridged)
details.Add("Abridged");
diff --git a/Source/LibationWinForms/grid/ProductsGrid.cs b/Source/LibationWinForms/grid/ProductsGrid.cs
index 2ab0f271..ba429dfc 100644
--- a/Source/LibationWinForms/grid/ProductsGrid.cs
+++ b/Source/LibationWinForms/grid/ProductsGrid.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using ApplicationServices;
+using DataLayer;
using Dinah.Core;
using Dinah.Core.DataBinding;
using Dinah.Core.Threading;
@@ -130,7 +131,7 @@ namespace LibationWinForms
var libraryBook = liveGridEntry.LibraryBook;
// liberated: open explorer to file
- if (libraryBook.Book.Audio_Exists)
+ if (libraryBook.Book.Audio_Exists())
{
var filePath = AudibleFileStorage.Audio.GetPath(libraryBook.Book.AudibleProductId);
if (!Go.To.File(filePath))