diff --git a/AaxDecrypter/AaxcDownloadConverter.cs b/AaxDecrypter/AaxcDownloadConverter.cs index f9490ecc..ef24b03e 100644 --- a/AaxDecrypter/AaxcDownloadConverter.cs +++ b/AaxDecrypter/AaxcDownloadConverter.cs @@ -224,6 +224,8 @@ namespace AaxDecrypter isCanceled = true; aaxFile?.Cancel(); aaxFile?.Dispose(); + nfsPersister?.NetworkFileStream?.Close(); + nfsPersister?.Dispose(); } } } diff --git a/AaxDecrypter/NetworkFileStream.cs b/AaxDecrypter/NetworkFileStream.cs index 5d7544b5..01b63781 100644 --- a/AaxDecrypter/NetworkFileStream.cs +++ b/AaxDecrypter/NetworkFileStream.cs @@ -241,9 +241,12 @@ namespace AaxDecrypter } while (downloadPosition < ContentLength && !isCancelled); _writeFile.Close(); + _networkStream.Close(); WritePosition = downloadPosition; Update(); - _networkStream.Close(); + + downloadedPiece.Set(); + downloadEnded.Set(); if (!isCancelled && WritePosition < ContentLength) throw new WebException($"Downloaded size (0x{WritePosition:X10}) is less than {nameof(ContentLength)} (0x{ContentLength:X10})."); @@ -251,7 +254,6 @@ namespace AaxDecrypter if (WritePosition > ContentLength) throw new WebException($"Downloaded size (0x{WritePosition:X10}) is greater than {nameof(ContentLength)} (0x{ContentLength:X10})."); - downloadEnded.Set(); } #endregion diff --git a/LibationWinForms/AsyncNotifyPropertyChanged.cs b/LibationWinForms/AsyncNotifyPropertyChanged.cs index 96f007ed..136930aa 100644 --- a/LibationWinForms/AsyncNotifyPropertyChanged.cs +++ b/LibationWinForms/AsyncNotifyPropertyChanged.cs @@ -8,7 +8,7 @@ namespace LibationWinForms { public event PropertyChangedEventHandler PropertyChanged; - protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") + public void NotifyPropertyChanged([CallerMemberName] string propertyName = "") => this.UIThread(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName))); } } diff --git a/LibationWinForms/BookLiberation/AudioDecodeForm.cs b/LibationWinForms/BookLiberation/AudioDecodeForm.cs index 4d8f66b8..aa3cfa3e 100644 --- a/LibationWinForms/BookLiberation/AudioDecodeForm.cs +++ b/LibationWinForms/BookLiberation/AudioDecodeForm.cs @@ -39,7 +39,6 @@ namespace LibationWinForms.BookLiberation #endregion #region IStreamable event handler overrides - public override void OnStreamingBegin(object sender, string beginString) { } public override void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress) { if (!downloadProgress.ProgressPercentage.HasValue) @@ -54,7 +53,6 @@ namespace LibationWinForms.BookLiberation public override void OnStreamingTimeRemaining(object sender, TimeSpan timeRemaining) => updateRemainingTime((int)timeRemaining.TotalSeconds); - public override void OnStreamingCompleted(object sender, string completedString) { } #endregion #region IAudioDecodable event handlers diff --git a/LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs b/LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs index dbf80104..8df2b4d5 100644 --- a/LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs +++ b/LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs @@ -48,7 +48,7 @@ namespace LibationWinForms.BookLiberation.BaseForms streamable.StreamingCompleted += OnStreamingCompleted; streamable.StreamingCompleted += OnStreamingCompletedClose; - FormClosed += UnsubscribeStreamable; + Disposed += UnsubscribeStreamable; } private void Subscribe(IProcessable processable) { @@ -81,7 +81,7 @@ namespace LibationWinForms.BookLiberation.BaseForms } private void UnsubscribeStreamable(object sender, EventArgs e) { - FormClosed -= UnsubscribeStreamable; + Disposed -= UnsubscribeStreamable; Streamable.StreamingBegin -= OnStreamingBeginShow; Streamable.StreamingBegin -= OnStreamingBegin; diff --git a/LibationWinForms/EditTagsDataGridViewImageButtonColumn.cs b/LibationWinForms/EditTagsDataGridViewImageButtonColumn.cs index f702d3fc..46ee85bd 100644 --- a/LibationWinForms/EditTagsDataGridViewImageButtonColumn.cs +++ b/LibationWinForms/EditTagsDataGridViewImageButtonColumn.cs @@ -22,12 +22,12 @@ namespace LibationWinForms var foreColor = tagsString?.Contains("hidden") == true ? HiddenForeColor : DataGridView.DefaultCellStyle.ForeColor; - if (DataGridView.Rows[RowIndex].DefaultCellStyle.ForeColor != foreColor) + if (DataGridView.Rows[rowIndex].DefaultCellStyle.ForeColor != foreColor) { - DataGridView.Rows[RowIndex].DefaultCellStyle.ForeColor = foreColor; + DataGridView.Rows[rowIndex].DefaultCellStyle.ForeColor = foreColor; } - if (tagsString.Length == 0) + if (tagsString?.Length == 0) { base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts); DrawButtonImage(graphics, ButtonImage, cellBounds); diff --git a/LibationWinForms/GridEntry.cs b/LibationWinForms/GridEntry.cs index 857469c6..7a90c437 100644 --- a/LibationWinForms/GridEntry.cs +++ b/LibationWinForms/GridEntry.cs @@ -155,37 +155,7 @@ namespace LibationWinForms #endregion #region Static library display functions - - public static (string mouseoverText, Bitmap buttonImage) GetLiberateDisplay(LiberatedState liberatedStatus, PdfState pdfStatus) - { - (string libState, string image_lib) = liberatedStatus switch - { - LiberatedState.Liberated => ("Liberated", "green"), - LiberatedState.PartialDownload => ("File has been at least\r\npartially downloaded", "yellow"), - LiberatedState.NotDownloaded => ("Book NOT downloaded", "red"), - _ => throw new Exception("Unexpected liberation state") - }; - - (string pdfState, string image_pdf) = pdfStatus switch - { - PdfState.Downloaded => ("\r\nPDF downloaded", "_pdf_yes"), - PdfState.NotDownloaded => ("\r\nPDF NOT downloaded", "_pdf_no"), - PdfState.NoPdf => ("", ""), - _ => throw new Exception("Unexpected PDF state") - }; - - var mouseoverText = libState + pdfState; - - if (liberatedStatus == LiberatedState.NotDownloaded || - liberatedStatus == LiberatedState.PartialDownload || - pdfStatus == PdfState.NotDownloaded) - mouseoverText += "\r\nClick to complete"; - - var buttonImage = (Bitmap)Properties.Resources.ResourceManager.GetObject($"liberate_{image_lib}{image_pdf}"); - - return (mouseoverText, buttonImage); - } - + /// /// This information should not change during lifetime, so call only once. /// diff --git a/LibationWinForms/LiberateDataGridViewImageButtonColumn.cs b/LibationWinForms/LiberateDataGridViewImageButtonColumn.cs index 6427677c..b8509e5d 100644 --- a/LibationWinForms/LiberateDataGridViewImageButtonColumn.cs +++ b/LibationWinForms/LiberateDataGridViewImageButtonColumn.cs @@ -22,12 +22,42 @@ namespace LibationWinForms if (value is (LiberatedState liberatedState, PdfState pdfState)) { - (string mouseoverText, Bitmap buttonImage) = GridEntry.GetLiberateDisplay(liberatedState, pdfState); + (string mouseoverText, Bitmap buttonImage) = GetLiberateDisplay(liberatedState, pdfState); DrawButtonImage(graphics, buttonImage, cellBounds); ToolTipText = mouseoverText; } } + + private static (string mouseoverText, Bitmap buttonImage) GetLiberateDisplay(LiberatedState liberatedStatus, PdfState pdfStatus) + { + (string libState, string image_lib) = liberatedStatus switch + { + LiberatedState.Liberated => ("Liberated", "green"), + LiberatedState.PartialDownload => ("File has been at least\r\npartially downloaded", "yellow"), + LiberatedState.NotDownloaded => ("Book NOT downloaded", "red"), + _ => throw new Exception("Unexpected liberation state") + }; + + (string pdfState, string image_pdf) = pdfStatus switch + { + PdfState.Downloaded => ("\r\nPDF downloaded", "_pdf_yes"), + PdfState.NotDownloaded => ("\r\nPDF NOT downloaded", "_pdf_no"), + PdfState.NoPdf => ("", ""), + _ => throw new Exception("Unexpected PDF state") + }; + + var mouseoverText = libState + pdfState; + + if (liberatedStatus == LiberatedState.NotDownloaded || + liberatedStatus == LiberatedState.PartialDownload || + pdfStatus == PdfState.NotDownloaded) + mouseoverText += "\r\nClick to complete"; + + var buttonImage = (Bitmap)Properties.Resources.ResourceManager.GetObject($"liberate_{image_lib}{image_pdf}"); + + return (mouseoverText, buttonImage); + } } } diff --git a/LibationWinForms/ProductsGrid.cs b/LibationWinForms/ProductsGrid.cs index 8e37cf8c..46b721a4 100644 --- a/LibationWinForms/ProductsGrid.cs +++ b/LibationWinForms/ProductsGrid.cs @@ -67,7 +67,7 @@ namespace LibationWinForms await Liberate_Click(liveGridEntry); break; case nameof(liveGridEntry.DisplayTags): - Details_Click(liveGridEntry.LibraryBook); + Details_Click(liveGridEntry); break; } } @@ -89,18 +89,21 @@ namespace LibationWinForms await BookLiberation.ProcessorAutomationController.BackupSingleBookAsync(libraryBook, (_, __) => RefreshRow(libraryBook.Book.AudibleProductId)); } - private void Details_Click(LibraryBook libraryBook) + private void Details_Click(GridEntry liveGridEntry) { - var bookDetailsForm = new BookDetailsDialog(libraryBook); + var bookDetailsForm = new BookDetailsDialog(liveGridEntry.LibraryBook); if (bookDetailsForm.ShowDialog() != DialogResult.OK) return; - var qtyChanges = LibraryCommands.UpdateUserDefinedItem(libraryBook.Book, bookDetailsForm.NewTags, bookDetailsForm.BookLiberatedStatus, bookDetailsForm.PdfLiberatedStatus); + var qtyChanges = LibraryCommands.UpdateUserDefinedItem(liveGridEntry.LibraryBook.Book, bookDetailsForm.NewTags, bookDetailsForm.BookLiberatedStatus, bookDetailsForm.PdfLiberatedStatus); if (qtyChanges == 0) return; //Re-apply filters Filter(); + + //Update whole GridEntry row + liveGridEntry.NotifyPropertyChanged(); } #endregion @@ -149,10 +152,10 @@ namespace LibationWinForms public void RefreshRow(string productId) { - var rowIndex = getRowIndex((ge) => ge.AudibleProductId == productId); + var liveGridEntry = getGridEntry((ge) => ge.AudibleProductId == productId); - // update cells incl Liberate button text - _dataGridView.InvalidateRow(rowIndex); + // 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(); @@ -193,7 +196,9 @@ namespace LibationWinForms #region DataGridView Macro - private int getRowIndex(Func func) => _dataGridView.GetRowIdOfBoundItem(func); + private GridEntry getGridEntry(Func predicate) + => ((SortableBindingList)gridEntryBindingSource.DataSource).FirstOrDefault(predicate); + private GridEntry getGridEntry(int rowIndex) => _dataGridView.GetBoundItem(rowIndex); #endregion