Add SeriesViewDialog
This commit is contained in:
parent
784ab73a36
commit
9ae1f0399b
27 changed files with 1293 additions and 18 deletions
49
Source/LibationWinForms/SeriesView/DownloadButtonColumn.cs
Normal file
49
Source/LibationWinForms/SeriesView/DownloadButtonColumn.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Source/LibationWinForms/SeriesView/SeriesEntryBindingList.cs
Normal file
46
Source/LibationWinForms/SeriesView/SeriesEntryBindingList.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Source/LibationWinForms/SeriesView/SeriesViewDialog.Designer.cs
generated
Normal file
62
Source/LibationWinForms/SeriesView/SeriesViewDialog.Designer.cs
generated
Normal 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
|
||||
}
|
||||
}
|
||||
193
Source/LibationWinForms/SeriesView/SeriesViewDialog.cs
Normal file
193
Source/LibationWinForms/SeriesView/SeriesViewDialog.cs
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Source/LibationWinForms/SeriesView/SeriesViewDialog.resx
Normal file
60
Source/LibationWinForms/SeriesView/SeriesViewDialog.resx
Normal 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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue