Add SeriesViewDialog

This commit is contained in:
MBucari 2023-03-19 20:05:18 -06:00 committed by Mbucari
parent 784ab73a36
commit 9ae1f0399b
27 changed files with 1293 additions and 18 deletions

View file

@ -0,0 +1,49 @@
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using LibationUiBase.SeriesView;
namespace LibationWinForms.SeriesView
{
public class DownloadButtonColumn : DataGridViewButtonColumn
{
public DownloadButtonColumn()
{
CellTemplate = new DownloadButtonColumnCell();
CellTemplate.Style.WrapMode = DataGridViewTriState.True;
}
}
internal class DownloadButtonColumnCell : DataGridViewButtonCell
{
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 (value is SeriesButton sentry)
{
string cellValue = sentry.DisplayText;
if (!sentry.Enabled)
{
//Draw disabled button
Rectangle buttonArea = cellBounds;
Rectangle buttonAdjustment = BorderWidths(advancedBorderStyle);
buttonArea.X += buttonAdjustment.X;
buttonArea.Y += buttonAdjustment.Y;
buttonArea.Height -= buttonAdjustment.Height;
buttonArea.Width -= buttonAdjustment.Width;
ButtonRenderer.DrawButton(graphics, buttonArea, cellValue, cellStyle.Font, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak, focused: false, PushButtonState.Disabled);
}
else if (sentry.HasButtonAction)
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, cellValue, cellValue, errorText, cellStyle, advancedBorderStyle, paintParts);
else
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
TextRenderer.DrawText(graphics, cellValue, cellStyle.Font, cellBounds, cellStyle.ForeColor);
}
}
else
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
}
}
}
}

View file

@ -0,0 +1,46 @@
using LibationUiBase.SeriesView;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace LibationWinForms.SeriesView
{
internal class SeriesEntryBindingList : BindingList<SeriesItem>
{
private PropertyDescriptor _propertyDescriptor;
private ListSortDirection _listSortDirection;
private bool _isSortedCore;
protected override PropertyDescriptor SortPropertyCore => _propertyDescriptor;
protected override ListSortDirection SortDirectionCore => _listSortDirection;
protected override bool IsSortedCore => _isSortedCore;
protected override bool SupportsSortingCore => true;
public SeriesEntryBindingList() : base(new List<SeriesItem>()) { }
public SeriesEntryBindingList(IEnumerable<SeriesItem> entries) : base(entries.ToList()) { }
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
var itemsList = (List<SeriesItem>)base.Items;
var sorted
= (direction == ListSortDirection.Ascending)
? itemsList.OrderBy(prop.GetValue).ToList()
: itemsList.OrderByDescending(prop.GetValue).ToList();
itemsList.Clear();
itemsList.AddRange(sorted);
_propertyDescriptor = prop;
_listSortDirection = direction;
_isSortedCore = true;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
}

View file

@ -0,0 +1,62 @@
using System.Windows.Forms;
namespace LibationWinForms.SeriesView
{
partial class SeriesViewDialog
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
tabControl1 = new TabControl();
SuspendLayout();
//
// tabControl1
//
tabControl1.Dock = DockStyle.Fill;
tabControl1.Location = new System.Drawing.Point(0, 0);
tabControl1.Name = "tabControl1";
tabControl1.SelectedIndex = 0;
tabControl1.Size = new System.Drawing.Size(800, 450);
tabControl1.TabIndex = 0;
//
// SeriesViewDialog
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(800, 450);
Controls.Add(tabControl1);
FormBorderStyle = FormBorderStyle.SizableToolWindow;
Name = "SeriesViewDialog";
StartPosition = FormStartPosition.CenterParent;
Text = "View All Items in Series";
ResumeLayout(false);
}
private TabControl tabControl1;
#endregion
}
}

View file

@ -0,0 +1,193 @@
using AudibleApi.Common;
using DataLayer;
using Dinah.Core;
using System.ComponentModel;
using System.Windows.Forms;
using System;
using Dinah.Core.WindowsDesktop.Forms;
using LibationWinForms.GridView;
using LibationFileManager;
using LibationUiBase.SeriesView;
using System.Drawing;
namespace LibationWinForms.SeriesView
{
public partial class SeriesViewDialog : Form
{
private readonly LibraryBook LibraryBook;
public SeriesViewDialog()
{
InitializeComponent();
this.RestoreSizeAndLocation(Configuration.Instance);
this.SetLibationIcon();
Load += SeriesViewDialog_Load;
FormClosing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance);
}
public SeriesViewDialog(LibraryBook libraryBook) : this()
{
LibraryBook = ArgumentValidator.EnsureNotNull(libraryBook, "libraryBook");
}
private async void SeriesViewDialog_Load(object sender, EventArgs e)
{
try
{
var seriesEntries = await SeriesItem.GetAllSeriesItemsAsync(LibraryBook);
//Create a DataGridView for each series and add all children of that series to it.
foreach (var series in seriesEntries.Keys)
{
var dgv = createNewSeriesGrid();
dgv.CellContentClick += Dgv_CellContentClick;
dgv.DataSource = new SeriesEntryBindingList(seriesEntries[series]);
dgv.BindingContextChanged += (_, _) => dgv.Sort(dgv.Columns["Order"], ListSortDirection.Ascending);
var tab = new TabPage { Text = series.Title };
tab.Controls.Add(dgv);
tab.VisibleChanged += (_, _) => dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
tabControl1.Controls.Add(tab);
}
}
catch (Exception ex)
{
Serilog.Log.Logger.Error(ex, "Error loading searies info");
var tab = new TabPage { Text = "ERROR" };
tab.Controls.Add(new Label { Text = "ERROR LOADING SERIES INFO\r\n\r\n" + ex.Message, ForeColor = Color.Red, Dock = DockStyle.Fill });
tabControl1.Controls.Add(tab);
}
}
private ImageDisplay imageDisplay;
private async void Dgv_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0) return;
var dgv = (DataGridView)sender;
var sentry = dgv.GetBoundItem<SeriesItem>(e.RowIndex);
if (dgv.Columns[e.ColumnIndex].DataPropertyName == nameof(SeriesItem.Cover))
{
coverClicked(sentry.Item);
return;
}
else if (dgv.Columns[e.ColumnIndex].DataPropertyName == nameof(SeriesItem.Title))
{
sentry.ViewOnAudible(LibraryBook.Book.Locale);
return;
}
else if (dgv.Columns[e.ColumnIndex].DataPropertyName == nameof(SeriesItem.Button) && sentry.Button.HasButtonAction)
{
await sentry.Button.PerformClickAsync(LibraryBook);
}
}
private void coverClicked(Item libraryBook)
{
var picDef = new PictureDefinition(libraryBook.PictureLarge ?? libraryBook.PictureId, PictureSize.Native);
void PictureCached(object sender, PictureCachedEventArgs e)
{
if (e.Definition.PictureId == picDef.PictureId)
imageDisplay.SetCoverArt(e.Picture);
PictureStorage.PictureCached -= PictureCached;
}
PictureStorage.PictureCached += PictureCached;
(bool isDefault, byte[] initialImageBts) = PictureStorage.GetPicture(picDef);
var windowTitle = $"{libraryBook.Title} - Cover";
if (imageDisplay is null || imageDisplay.IsDisposed || !imageDisplay.Visible)
{
imageDisplay = new ImageDisplay();
imageDisplay.RestoreSizeAndLocation(Configuration.Instance);
imageDisplay.FormClosed += (_, _) => imageDisplay.SaveSizeAndLocation(Configuration.Instance);
}
imageDisplay.Text = windowTitle;
imageDisplay.SetCoverArt(initialImageBts);
if (!isDefault)
PictureStorage.PictureCached -= PictureCached;
if (!imageDisplay.Visible)
imageDisplay.Show();
}
private static DataGridView createNewSeriesGrid()
{
var dgv = new DataGridView
{
Dock = DockStyle.Fill,
RowHeadersVisible = false,
ReadOnly = false,
ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize,
AllowUserToAddRows = false,
AllowUserToDeleteRows = false,
AllowUserToResizeRows = false,
AutoGenerateColumns = false
};
dgv.RowTemplate.Height = 80;
dgv.Columns.Add(new DataGridViewImageColumn
{
DataPropertyName = nameof(SeriesItem.Cover),
HeaderText = "Cover",
Name = "Cover",
ReadOnly = true,
Resizable = DataGridViewTriState.False,
Width = 80
});
dgv.Columns.Add(new DataGridViewTextBoxColumn
{
DataPropertyName = nameof(SeriesItem.Order),
HeaderText = "Series\r\nOrder",
Name = "Order",
ReadOnly = true,
SortMode = DataGridViewColumnSortMode.Automatic,
Width = 50
});
dgv.Columns.Add(new DownloadButtonColumn
{
DataPropertyName = nameof(SeriesItem.Button),
HeaderText = "Availability",
Name = "DownloadButton",
ReadOnly = true,
SortMode = DataGridViewColumnSortMode.Automatic,
Width = 50
});
dgv.Columns.Add(new DataGridViewLinkColumn
{
DataPropertyName = nameof(SeriesItem.Title),
HeaderText = "Title",
Name = "Title",
ReadOnly = true,
TrackVisitedState = true,
SortMode = DataGridViewColumnSortMode.Automatic,
Width = 200,
});
dgv.CellToolTipTextNeeded += Dgv_CellToolTipTextNeeded;
return dgv;
}
private static void Dgv_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e)
{
if (sender is not DataGridView dgv || e.ColumnIndex < 0) return;
e.ToolTipText = dgv.Columns[e.ColumnIndex].DataPropertyName switch
{
nameof(SeriesItem.Cover) => "Click to see full size",
nameof(SeriesItem.Title) => "Open Audible product page",
_ => string.Empty
};
}
}
}

View file

@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>