Add debug constants and don't check updates in debug.

Refactored cell formatting

Made GridEntry thread safe

Moved PictureStorage set defaults into constructor.
This commit is contained in:
Michael Bucari-Tovo 2021-08-09 20:07:15 -06:00
parent ab82e7c99c
commit 2ef746a94c
7 changed files with 49 additions and 94 deletions

View File

@ -13,7 +13,11 @@
<!-- <PublishSingleFile>true</PublishSingleFile> --> <!-- <PublishSingleFile>true</PublishSingleFile> -->
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<Version>5.4.9.79</Version> <Version>5.4.9.120</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -59,7 +59,10 @@ namespace LibationLauncher
ensureSerilogConfig(config); ensureSerilogConfig(config);
configureLogging(config); configureLogging(config);
logStartupState(config); logStartupState(config);
#if !DEBUG
checkForUpdate(config); checkForUpdate(config);
#endif
Application.Run(new Form1()); Application.Run(new Form1());
} }
@ -145,7 +148,7 @@ namespace LibationLauncher
CancelInstallation(); CancelInstallation();
} }
#region migrate to v5.0.0 re-register device if device info not in settings #region migrate to v5.0.0 re-register device if device info not in settings
private static void migrate_to_v5_0_0(Configuration config) private static void migrate_to_v5_0_0(Configuration config)
{ {
if (!config.Exists(nameof(config.AllowLibationFixup))) if (!config.Exists(nameof(config.AllowLibationFixup)))
@ -187,9 +190,9 @@ namespace LibationLauncher
} }
} }
} }
#endregion #endregion
#region migrate to v5.2.0 #region migrate to v5.2.0
// get rid of meta-directories, combine DownloadsInProgressEnum and DecryptInProgressEnum => InProgress // get rid of meta-directories, combine DownloadsInProgressEnum and DecryptInProgressEnum => InProgress
private static void migrate_to_v5_2_0__pre_config() private static void migrate_to_v5_2_0__pre_config()
{ {
@ -231,9 +234,9 @@ namespace LibationLauncher
if (!config.Exists(nameof(config.DecryptToLossy))) if (!config.Exists(nameof(config.DecryptToLossy)))
config.DecryptToLossy = false; config.DecryptToLossy = false;
} }
#endregion #endregion
#region migrate to v5.4.1 see comment #region migrate to v5.4.1 see comment
// this 'migration' is a bit different. it intentionally runs each time Libation is started. its job will be fulfilled when I eventually // this 'migration' is a bit different. it intentionally runs each time Libation is started. its job will be fulfilled when I eventually
// implement the portion which removes FilePaths.json, at which time this method will be a proper migration // implement the portion which removes FilePaths.json, at which time this method will be a proper migration
// //
@ -297,7 +300,7 @@ namespace LibationLauncher
debugStopwatch.Stop(); debugStopwatch.Stop();
var debugTotal = debugStopwatch.Elapsed; var debugTotal = debugStopwatch.Elapsed;
} }
#endregion #endregion
private static void ensureSerilogConfig(Configuration config) private static void ensureSerilogConfig(Configuration config)
{ {
@ -418,6 +421,7 @@ namespace LibationLauncher
if (latest is null) if (latest is null)
return; return;
var latestVersionString = latest.TagName.Trim('v'); var latestVersionString = latest.TagName.Trim('v');
if (!Version.TryParse(latestVersionString, out var latestRelease)) if (!Version.TryParse(latestVersionString, out var latestRelease))
return; return;

View File

@ -39,8 +39,8 @@ namespace LibationWinForms.Dialogs
dataGridView1.BindingContextChanged += (s, e) => UpdateSelection(); dataGridView1.BindingContextChanged += (s, e) => UpdateSelection();
var orderedGridEntries = _libraryBooks var orderedGridEntries = _libraryBooks
.Select(lb => new RemovableGridEntry(new GridEntry(lb))) .Select(lb => new RemovableGridEntry(lb))
.OrderByDescending(ge => ge.GridEntry.PurchaseDate) .OrderByDescending(ge => ge.PurchaseDate)
.ToList(); .ToList();
_removableGridEntries = orderedGridEntries.ToSortableBindingList(); _removableGridEntries = orderedGridEntries.ToSortableBindingList();
@ -65,7 +65,7 @@ namespace LibationWinForms.Dialogs
{ {
var rmovedBooks = await LibraryCommands.FindInactiveBooks((account) => new WinformResponder(account), _libraryBooks, _accounts); var rmovedBooks = await LibraryCommands.FindInactiveBooks((account) => new WinformResponder(account), _libraryBooks, _accounts);
var removable = _removableGridEntries.Where(rge => rmovedBooks.Count(rb => rb.Book.AudibleProductId == rge.GridEntry.AudibleProductId) == 1); var removable = _removableGridEntries.Where(rge => rmovedBooks.Count(rb => rb.Book.AudibleProductId == rge.AudibleProductId) == 1);
if (removable.Count() == 0) if (removable.Count() == 0)
return; return;
@ -110,7 +110,7 @@ namespace LibationWinForms.Dialogs
var libBooks = context.GetLibrary_Flat_NoTracking(); var libBooks = context.GetLibrary_Flat_NoTracking();
var removeLibraryBooks = libBooks.Where(lb => selected.Count(rge => rge.GridEntry.AudibleProductId == lb.Book.AudibleProductId) == 1).ToArray(); var removeLibraryBooks = libBooks.Where(lb => selected.Count(rge => rge.AudibleProductId == lb.Book.AudibleProductId) == 1).ToArray();
context.Library.RemoveRange(removeLibraryBooks); context.Library.RemoveRange(removeLibraryBooks);
context.SaveChanges(); context.SaveChanges();
BooksRemoved = true; BooksRemoved = true;
@ -141,11 +141,8 @@ namespace LibationWinForms.Dialogs
} }
internal class RemovableGridEntry : INotifyPropertyChanged internal class RemovableGridEntry : GridEntry
{ {
public event PropertyChangedEventHandler PropertyChanged;
public GridEntry GridEntry { get; }
public bool Remove public bool Remove
{ {
get get
@ -160,51 +157,12 @@ namespace LibationWinForms.Dialogs
NotifyPropertyChanged(); NotifyPropertyChanged();
} }
} }
} }
public Image Cover
{
get
{
return _cover;
}
set
{
_cover = value;
NotifyPropertyChanged();
}
}
public string Title => GridEntry.Title;
public string Authors => GridEntry.Authors;
public string Misc => GridEntry.Misc;
public string DatePurchased => GridEntry.PurchaseDate;
private bool _remove = false; private bool _remove = false;
private Image _cover;
public RemovableGridEntry(GridEntry gridEntry) public RemovableGridEntry(LibraryBook libraryBook) :base(libraryBook)
{ {
GridEntry = gridEntry;
var picDef = new FileManager.PictureDefinition(GridEntry.LibraryBook.Book.PictureId, FileManager.PictureSize._80x80);
(bool isDefault, byte[] picture) = FileManager.PictureStorage.GetPicture(picDef);
if (isDefault)
FileManager.PictureStorage.PictureCached += PictureStorage_PictureCached;
_cover = ImageReader.ToImage(picture);
} }
private void PictureStorage_PictureCached(object sender, string pictureId)
{
if (pictureId == GridEntry.LibraryBook.Book.PictureId)
{
Cover = WindowsDesktopUtilities.WinAudibleImageServer.GetImage(pictureId, FileManager.PictureSize._80x80);
FileManager.PictureStorage.PictureCached -= PictureStorage_PictureCached;
}
}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }
} }

View File

@ -12,15 +12,23 @@ namespace LibationWinForms
internal class EditTagsDataGridViewImageButtonCell : DataGridViewImageButtonCell internal class EditTagsDataGridViewImageButtonCell : DataGridViewImageButtonCell
{ {
private static readonly Bitmap ButtonImage = Properties.Resources.edit_tags_25x25; private static readonly Bitmap ButtonImage = Properties.Resources.edit_tags_25x25;
private static readonly Color HiddenForeColor = Color.LightGray;
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{ {
if (((string)value).Length == 0) var valueString = (string)value;
DataGridView.Rows[RowIndex].DefaultCellStyle.ForeColor = valueString?.Contains("hidden") == true ? HiddenForeColor : DataGridView.DefaultCellStyle.ForeColor;
if (valueString.Length == 0)
{ {
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts); base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts);
DrawImage(graphics, ButtonImage, cellBounds); DrawImage(graphics, ButtonImage, cellBounds);
} }
else else
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
}
} }
} }
} }

View File

@ -48,13 +48,6 @@ namespace LibationWinForms
this.Load += (_, __) => RestoreSizeAndLocation(); this.Load += (_, __) => RestoreSizeAndLocation();
this.Load += (_, __) => RefreshImportMenu(); this.Load += (_, __) => RefreshImportMenu();
// start background service
this.Load += (_, __) => startBackgroundImageDownloader();
}
private static void startBackgroundImageDownloader()
{
// load default/missing cover images. this will also initiate the background image downloader
var format = System.Drawing.Imaging.ImageFormat.Jpeg; var format = System.Drawing.Imaging.ImageFormat.Jpeg;
PictureStorage.SetDefaultImage(PictureSize._80x80, Properties.Resources.default_cover_80x80.ToBytes(format)); PictureStorage.SetDefaultImage(PictureSize._80x80, Properties.Resources.default_cover_80x80.ToBytes(format));
PictureStorage.SetDefaultImage(PictureSize._300x300, Properties.Resources.default_cover_300x300.ToBytes(format)); PictureStorage.SetDefaultImage(PictureSize._300x300, Properties.Resources.default_cover_300x300.ToBytes(format));

View File

@ -5,9 +5,11 @@ using System.ComponentModel;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading;
using ApplicationServices; using ApplicationServices;
using DataLayer; using DataLayer;
using Dinah.Core.Drawing; using Dinah.Core.Drawing;
using Dinah.Core.Windows.Forms;
namespace LibationWinForms namespace LibationWinForms
{ {
@ -32,6 +34,7 @@ namespace LibationWinForms
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
private Book Book => LibraryBook.Book; private Book Book => LibraryBook.Book;
private SynchronizationContext SyncContext { get; } = SynchronizationContext.Current;
private Image _cover; private Image _cover;
public GridEntry(LibraryBook libraryBook) public GridEntry(LibraryBook libraryBook)
@ -72,16 +75,23 @@ namespace LibationWinForms
{ {
if (pictureId == Book.PictureId) if (pictureId == Book.PictureId)
{ {
//GridEntry SHOULD be UI-ignorant, but PropertyChanged
Cover = WindowsDesktopUtilities.WinAudibleImageServer.GetImage(pictureId, FileManager.PictureSize._80x80); Cover = WindowsDesktopUtilities.WinAudibleImageServer.GetImage(pictureId, FileManager.PictureSize._80x80);
FileManager.PictureStorage.PictureCached -= PictureStorage_PictureCached; FileManager.PictureStorage.PictureCached -= PictureStorage_PictureCached;
} }
} }
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") => protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); => SyncContext.Post(
args => OnPropertyChangedAsync(args as AsyncCompletedEventArgs),
new AsyncCompletedEventArgs(null, false, new PropertyChangedEventArgs(propertyName))
);
#region Data Source properties private void OnPropertyChangedAsync(AsyncCompletedEventArgs e) =>
public Image Cover PropertyChanged?.Invoke(this, e.UserState as PropertyChangedEventArgs);
#region Data Source properties
public Image Cover
{ {
get get
{ {

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Drawing;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
@ -38,7 +37,6 @@ namespace LibationWinForms
// sorting breaks filters. must reapply filters after sorting // sorting breaks filters. must reapply filters after sorting
_dataGridView.Sorted += (_, __) => Filter(); _dataGridView.Sorted += (_, __) => Filter();
_dataGridView.CellFormatting += HiddenFormatting;
_dataGridView.CellContentClick += DataGridView_CellContentClick; _dataGridView.CellContentClick += DataGridView_CellContentClick;
EnableDoubleBuffering(); EnableDoubleBuffering();
@ -133,7 +131,7 @@ namespace LibationWinForms
var orderedGridEntries = lib var orderedGridEntries = lib
.Select(lb => new GridEntry(lb)).ToList() .Select(lb => new GridEntry(lb)).ToList()
// default load order // default load order
.OrderByDescending(ge => ge.PurchaseDate) .OrderByDescending(ge => (DateTime)ge.GetMemberValue(nameof(ge.PurchaseDate)))
//// more advanced example: sort by author, then series, then title //// more advanced example: sort by author, then series, then title
//.OrderBy(ge => ge.Authors) //.OrderBy(ge => ge.Authors)
// .ThenBy(ge => ge.Series) // .ThenBy(ge => ge.Series)
@ -155,10 +153,10 @@ namespace LibationWinForms
public void RefreshRow(string productId) public void RefreshRow(string productId)
{ {
var rowId = getRowIndex((ge) => ge.AudibleProductId == productId); var rowIndex = getRowIndex((ge) => ge.AudibleProductId == productId);
// update cells incl Liberate button text // update cells incl Liberate button text
_dataGridView.InvalidateRow(rowId); _dataGridView.InvalidateRow(rowIndex);
// needed in case filtering by -IsLiberated and it gets changed to Liberated. want to immediately show the change // needed in case filtering by -IsLiberated and it gets changed to Liberated. want to immediately show the change
Filter(); Filter();
@ -166,28 +164,9 @@ namespace LibationWinForms
BackupCountsChanged?.Invoke(this, EventArgs.Empty); BackupCountsChanged?.Invoke(this, EventArgs.Empty);
} }
#region format text cells. ie: not buttons
private void HiddenFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
var dgv = (DataGridView)sender;
// no action needed for buttons
if (e.RowIndex < 0 || dgv.Columns[e.ColumnIndex] is DataGridViewButtonColumn)
return;
var isHidden = getGridEntry(e.RowIndex).TagsEnumerated.Contains("hidden");
getCell(e).Style
= isHidden
? new DataGridViewCellStyle { ForeColor = Color.LightGray }
: dgv.DefaultCellStyle;
}
#endregion #endregion
#endregion #region Filter
#region filter
string _filterSearchString; string _filterSearchString;
private void Filter() => Filter(_filterSearchString); private void Filter() => Filter(_filterSearchString);
@ -220,7 +199,6 @@ namespace LibationWinForms
private int getRowIndex(Func<GridEntry, bool> func) => _dataGridView.GetRowIdOfBoundItem(func); private int getRowIndex(Func<GridEntry, bool> func) => _dataGridView.GetRowIdOfBoundItem(func);
private GridEntry getGridEntry(int rowIndex) => _dataGridView.GetBoundItem<GridEntry>(rowIndex); private GridEntry getGridEntry(int rowIndex) => _dataGridView.GetBoundItem<GridEntry>(rowIndex);
private DataGridViewCell getCell(DataGridViewCellFormattingEventArgs e) => _dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex];
#endregion #endregion
} }