diff --git a/ApplicationServices/LibraryCommands.cs b/ApplicationServices/LibraryCommands.cs
index d544a77f..1d428237 100644
--- a/ApplicationServices/LibraryCommands.cs
+++ b/ApplicationServices/LibraryCommands.cs
@@ -163,6 +163,7 @@ namespace ApplicationServices
using var context = DbContexts.GetContext();
var udi = libraryBook.UserDefinedItem;
+ udi.Tags = newTags;
// Attach() NoTracking entities before SaveChanges()
context.Attach(udi).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
@@ -186,6 +187,7 @@ namespace ApplicationServices
using var context = DbContexts.GetContext();
var udi = libraryBook.UserDefinedItem;
+ udi.BookStatus = liberatedStatus;
// Attach() NoTracking entities before SaveChanges()
context.Attach(udi).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
@@ -209,6 +211,7 @@ namespace ApplicationServices
using var context = DbContexts.GetContext();
var udi = libraryBook.UserDefinedItem;
+ udi.PdfStatus = liberatedStatus;
// Attach() NoTracking entities before SaveChanges()
context.Attach(udi).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
diff --git a/DataLayer/EfClasses/UserDefinedItem.cs b/DataLayer/EfClasses/UserDefinedItem.cs
index 18bb4fd5..5bd52beb 100644
--- a/DataLayer/EfClasses/UserDefinedItem.cs
+++ b/DataLayer/EfClasses/UserDefinedItem.cs
@@ -44,8 +44,12 @@ namespace DataLayer
get => _tags;
set
{
- _tags = sanitize(value);
- ItemChanged?.Invoke(this, nameof(Tags));
+ var newTags = sanitize(value);
+ if (_tags != newTags)
+ {
+ _tags = newTags;
+ ItemChanged?.Invoke(this, nameof(Tags));
+ }
}
}
diff --git a/LibationWinForms/Form1.cs b/LibationWinForms/Form1.cs
index 8a1a1fb5..134a2123 100644
--- a/LibationWinForms/Form1.cs
+++ b/LibationWinForms/Form1.cs
@@ -384,15 +384,14 @@ namespace LibationWinForms
#region liberate menu
private async void beginBookBackupsToolStripMenuItem_Click(object sender, EventArgs e)
- => await BookLiberation.ProcessorAutomationController.BackupAllBooksAsync(updateGridRow);
+ => await BookLiberation.ProcessorAutomationController.BackupAllBooksAsync();
private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e)
- => await BookLiberation.ProcessorAutomationController.BackupAllPdfsAsync(updateGridRow);
+ => await BookLiberation.ProcessorAutomationController.BackupAllPdfsAsync();
private async void convertAllM4bToMp3ToolStripMenuItem_Click(object sender, EventArgs e)
=> await BookLiberation.ProcessorAutomationController.ConvertAllBooksAsync();
- private void updateGridRow(object _, LibraryBook libraryBook) => currProductsGrid.RefreshLiberatedStatus(libraryBook);
#endregion
#region Export menu
diff --git a/LibationWinForms/GridEntry.cs b/LibationWinForms/GridEntry.cs
index d6f414bf..b2184d6e 100644
--- a/LibationWinForms/GridEntry.cs
+++ b/LibationWinForms/GridEntry.cs
@@ -12,6 +12,9 @@ using Dinah.Core.Drawing;
namespace LibationWinForms
{
+ ///
+ /// The View Model for a LibraryBook
+ ///
internal class GridEntry : AsyncNotifyPropertyChanged, IMemberComparable
{
#region implementation properties
@@ -26,12 +29,15 @@ namespace LibationWinForms
private Book Book => LibraryBook.Book;
private Image _cover;
+ private Action _refilter;
- public GridEntry(LibraryBook libraryBook)
+ public GridEntry(LibraryBook libraryBook, Action refilterOnChanged = null)
{
LibraryBook = libraryBook;
+ _refilter = refilterOnChanged;
_memberValues = CreateMemberValueDictionary();
+
//Get cover art. If it's default, subscribe to PictureCached
{
(bool isDefault, byte[] picture) = FileManager.PictureStorage.GetPicture(new FileManager.PictureDefinition(Book.PictureId, FileManager.PictureSize._80x80));
@@ -58,7 +64,7 @@ namespace LibationWinForms
Description = GetDescriptionDisplay(Book);
}
- //DisplayTags and Liberate properties are live.
+ UserDefinedItem.ItemChanged += UserDefinedItem_ItemChanged;
}
private void PictureStorage_PictureCached(object sender, FileManager.PictureCachedEventArgs e)
@@ -70,7 +76,48 @@ namespace LibationWinForms
}
}
- #region Data Source properties
+ #region detect changes to the model and update the view
+
+ ///
+ /// This event handler receives notifications from the model that it has changed.
+ /// Save to the database and notify the view that it's changed.
+ ///
+ private void UserDefinedItem_ItemChanged(object sender, string itemName)
+ {
+ var udi = sender as UserDefinedItem;
+
+ if (udi.Book.AudibleProductId != LibraryBook.Book.AudibleProductId)
+ return;
+
+ switch (itemName)
+ {
+ case nameof(udi.Tags):
+ {
+ LibraryCommands.UpdateTags(LibraryBook.Book, udi.Tags);
+ NotifyPropertyChanged(nameof(DisplayTags));
+ }
+ break;
+ case nameof(udi.BookStatus):
+ {
+ var status = udi.BookStatus == LiberatedStatus.PartialDownload ? LiberatedStatus.NotLiberated : udi.BookStatus;
+ LibraryCommands.UpdateBook(LibraryBook.Book, status);
+ NotifyPropertyChanged(nameof(Liberate));
+ }
+ break;
+ case nameof(udi.PdfStatus):
+ {
+ LibraryCommands.UpdatePdf(LibraryBook.Book, udi.PdfStatus);
+ NotifyPropertyChanged(nameof(Liberate));
+ }
+ break;
+ }
+
+ _refilter?.Invoke();
+ }
+
+ #endregion
+
+ #region Model properties exposed to the view
public Image Cover
{
get
@@ -95,8 +142,22 @@ namespace LibationWinForms
public string Category { get; }
public string Misc { get; }
public string Description { get; }
- public string DisplayTags => string.Join("\r\n", Book.UserDefinedItem.TagsEnumerated);
- public (LiberatedStatus BookStatus, LiberatedStatus? PdfStatus) Liberate => (LibraryCommands.Liberated_Status(Book), LibraryCommands.Pdf_Status(Book));
+ public string DisplayTags
+ {
+ get=> Book.UserDefinedItem.Tags;
+ set => Book.UserDefinedItem.Tags = value;
+ }
+ public (LiberatedStatus BookStatus, LiberatedStatus? PdfStatus) Liberate
+ {
+ get => (LibraryCommands.Liberated_Status(LibraryBook.Book), LibraryCommands.Pdf_Status(LibraryBook.Book));
+
+ set
+ {
+ LibraryBook.Book.UserDefinedItem.BookStatus = value.BookStatus;
+ LibraryBook.Book.UserDefinedItem.PdfStatus = value.PdfStatus;
+ }
+ }
+
#endregion
#region Data Sorting
@@ -199,5 +260,12 @@ namespace LibationWinForms
}
#endregion
+
+ ~GridEntry()
+ {
+ UserDefinedItem.ItemChanged -= UserDefinedItem_ItemChanged;
+ FileManager.PictureStorage.PictureCached -= PictureStorage_PictureCached;
+ }
}
+
}
diff --git a/LibationWinForms/ProductsGrid.cs b/LibationWinForms/ProductsGrid.cs
index 46b721a4..043c0a1e 100644
--- a/LibationWinForms/ProductsGrid.cs
+++ b/LibationWinForms/ProductsGrid.cs
@@ -86,7 +86,7 @@ namespace LibationWinForms
}
// else: liberate
- await BookLiberation.ProcessorAutomationController.BackupSingleBookAsync(libraryBook, (_, __) => RefreshRow(libraryBook.Book.AudibleProductId));
+ await BookLiberation.ProcessorAutomationController.BackupSingleBookAsync(libraryBook);
}
private void Details_Click(GridEntry liveGridEntry)
@@ -95,15 +95,10 @@ namespace LibationWinForms
if (bookDetailsForm.ShowDialog() != DialogResult.OK)
return;
- var qtyChanges = LibraryCommands.UpdateUserDefinedItem(liveGridEntry.LibraryBook.Book, bookDetailsForm.NewTags, bookDetailsForm.BookLiberatedStatus, bookDetailsForm.PdfLiberatedStatus);
- if (qtyChanges == 0)
- return;
+ liveGridEntry.DisplayTags = bookDetailsForm.NewTags;
+ liveGridEntry.Liberate = (bookDetailsForm.BookLiberatedStatus, bookDetailsForm.PdfLiberatedStatus);
- //Re-apply filters
- Filter();
-
- //Update whole GridEntry row
- liveGridEntry.NotifyPropertyChanged();
+ BackupCountsChanged?.Invoke(this, EventArgs.Empty);
}
#endregion
@@ -132,7 +127,7 @@ namespace LibationWinForms
}
var orderedGridEntries = lib
- .Select(lb => new GridEntry(lb)).ToList()
+ .Select(lb => new GridEntry(lb, Filter)).ToList()
// default load order
.OrderByDescending(ge => (DateTime)ge.GetMemberValue(nameof(ge.PurchaseDate)))
//// more advanced example: sort by author, then series, then title
@@ -150,19 +145,6 @@ namespace LibationWinForms
BackupCountsChanged?.Invoke(this, EventArgs.Empty);
}
- public void RefreshRow(string productId)
- {
- var liveGridEntry = getGridEntry((ge) => ge.AudibleProductId == productId);
-
- // update GridEntry Liberate cell
- liveGridEntry?.NotifyPropertyChanged(nameof(liveGridEntry.Liberate));
-
- // needed in case filtering by -IsLiberated and it gets changed to Liberated. want to immediately show the change
- Filter();
-
- BackupCountsChanged?.Invoke(this, EventArgs.Empty);
- }
-
#endregion
#region Filter
@@ -195,12 +177,7 @@ namespace LibationWinForms
#endregion
#region DataGridView Macro
-
- private GridEntry getGridEntry(Func predicate)
- => ((SortableBindingList)gridEntryBindingSource.DataSource).FirstOrDefault(predicate);
-
private GridEntry getGridEntry(int rowIndex) => _dataGridView.GetBoundItem(rowIndex);
-
#endregion
}
}