Add clip and bookmark viewer and exporter

This commit is contained in:
Michael Bucari-Tovo 2023-01-05 23:40:39 -07:00
parent 6417aee780
commit 7eaa03e43c
10 changed files with 529 additions and 52 deletions

View file

@ -44,6 +44,7 @@
this.deleteCheckedBtn = new System.Windows.Forms.Button();
this.exportAllBtn = new System.Windows.Forms.Button();
this.exportCheckedBtn = new System.Windows.Forms.Button();
this.reloadAllBtn = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
@ -70,7 +71,7 @@
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.RowHeadersVisible = false;
this.dataGridView1.RowTemplate.Height = 25;
this.dataGridView1.Size = new System.Drawing.Size(334, 291);
this.dataGridView1.Size = new System.Drawing.Size(491, 291);
this.dataGridView1.TabIndex = 0;
//
// checkboxColumn
@ -158,7 +159,7 @@
this.deleteCheckedBtn.Location = new System.Drawing.Point(115, 297);
this.deleteCheckedBtn.Margin = new System.Windows.Forms.Padding(20, 3, 3, 3);
this.deleteCheckedBtn.Name = "deleteCheckedBtn";
this.deleteCheckedBtn.Size = new System.Drawing.Size(61, 52);
this.deleteCheckedBtn.Size = new System.Drawing.Size(97, 23);
this.deleteCheckedBtn.TabIndex = 3;
this.deleteCheckedBtn.Text = "Delete Checked";
this.deleteCheckedBtn.UseVisualStyleBackColor = true;
@ -167,7 +168,7 @@
// exportAllBtn
//
this.exportAllBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.exportAllBtn.Location = new System.Drawing.Point(221, 326);
this.exportAllBtn.Location = new System.Drawing.Point(378, 326);
this.exportAllBtn.Name = "exportAllBtn";
this.exportAllBtn.Size = new System.Drawing.Size(101, 23);
this.exportAllBtn.TabIndex = 4;
@ -178,7 +179,7 @@
// exportCheckedBtn
//
this.exportCheckedBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.exportCheckedBtn.Location = new System.Drawing.Point(221, 297);
this.exportCheckedBtn.Location = new System.Drawing.Point(378, 297);
this.exportCheckedBtn.Name = "exportCheckedBtn";
this.exportCheckedBtn.Size = new System.Drawing.Size(101, 23);
this.exportCheckedBtn.TabIndex = 5;
@ -186,11 +187,24 @@
this.exportCheckedBtn.UseVisualStyleBackColor = true;
this.exportCheckedBtn.Click += new System.EventHandler(this.exportCheckedBtn_Click);
//
// reloadAllBtn
//
this.reloadAllBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.reloadAllBtn.Location = new System.Drawing.Point(115, 326);
this.reloadAllBtn.Margin = new System.Windows.Forms.Padding(20, 3, 3, 3);
this.reloadAllBtn.Name = "reloadAllBtn";
this.reloadAllBtn.Size = new System.Drawing.Size(97, 23);
this.reloadAllBtn.TabIndex = 6;
this.reloadAllBtn.Text = "Reload All";
this.reloadAllBtn.UseVisualStyleBackColor = true;
this.reloadAllBtn.Click += new System.EventHandler(this.reloadAllBtn_Click);
//
// BookRecordsDialog
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(334, 361);
this.ClientSize = new System.Drawing.Size(491, 361);
this.Controls.Add(this.reloadAllBtn);
this.Controls.Add(this.exportCheckedBtn);
this.Controls.Add(this.exportAllBtn);
this.Controls.Add(this.deleteCheckedBtn);
@ -200,7 +214,7 @@
this.KeyPreview = true;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(350, 400);
this.MinimumSize = new System.Drawing.Size(507, 400);
this.Name = "BookRecordsDialog";
this.Text = "Book Dialog";
this.Shown += new System.EventHandler(this.BookRecordsDialog_Shown);
@ -227,5 +241,6 @@
private System.Windows.Forms.DataGridViewTextBoxColumn endTimeColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn noteColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn titleColumn;
private System.Windows.Forms.Button reloadAllBtn;
}
}

View file

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LibationWinForms.Dialogs
@ -74,11 +75,30 @@ namespace LibationWinForms.Dialogs
#region Buttons
private void exportCheckedBtn_Click(object sender, EventArgs e)
=> saveRecords(bookRecordEntries.Where(r => r.IsChecked).Select(r => r.Record));
private void setControlEnabled(object control, bool enabled)
{
if (control is Control c)
{
if (c.InvokeRequired)
c.Invoke(new MethodInvoker(() => c.Enabled = enabled));
else
c.Enabled = enabled;
}
}
private void exportAllBtn_Click(object sender, EventArgs e)
=> saveRecords(bookRecordEntries.Select(r => r.Record));
private async void exportCheckedBtn_Click(object sender, EventArgs e)
{
setControlEnabled(sender, false);
await saveRecords(bookRecordEntries.Where(r => r.IsChecked).Select(r => r.Record));
setControlEnabled(sender, true);
}
private async void exportAllBtn_Click(object sender, EventArgs e)
{
setControlEnabled(sender, false);
await saveRecords(bookRecordEntries.Select(r => r.Record));
setControlEnabled(sender, true);
}
private void uncheckAllBtn_Click(object sender, EventArgs e)
{
@ -98,6 +118,8 @@ namespace LibationWinForms.Dialogs
if (!records.Any()) return;
setControlEnabled(sender, false);
bool success = false;
try
{
@ -114,26 +136,49 @@ namespace LibationWinForms.Dialogs
{
Serilog.Log.Error(ex, ex.Message);
}
finally { setControlEnabled(sender, true); }
if (!success)
MessageBox.Show(this, $"Libation was unable to delete the {records.Count} selected records", "Deletion Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
private async void reloadAllBtn_Click(object sender, EventArgs e)
{
setControlEnabled(sender, false);
try
{
var api = await libraryBook.GetApiAsync();
var records = await api.GetRecordsAsync(libraryBook.Book.AudibleProductId);
bookRecordEntries = new BookRecordBindingList(records.Select(r => new BookRecordEntry(r)));
syncBindingSource.DataSource = bookRecordEntries;
}
catch (Exception ex)
{
Serilog.Log.Error(ex, ex.Message);
MessageBox.Show(this, $"Libation was unable to to reload records", "Reload Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally { setControlEnabled(sender, true); }
}
#endregion
private void saveRecords(IEnumerable<IRecord> records)
private async Task saveRecords(IEnumerable<IRecord> records)
{
try
{
var saveFileDialog = new SaveFileDialog
{
Title = "Where to export records",
AddExtension = true,
FileName = $"{libraryBook.Book.Title} - Records",
DefaultExt = "xlsx",
Filter = "Excel Workbook (*.xlsx)|*.xlsx|CSV files (*.csv)|*.csv|JSON files (*.json)|*.json" // + "|All files (*.*)|*.*"
};
var saveFileDialog =
Invoke(() => new SaveFileDialog
{
Title = "Where to export records",
AddExtension = true,
FileName = $"{libraryBook.Book.Title} - Records",
DefaultExt = "xlsx",
Filter = "Excel Workbook (*.xlsx)|*.xlsx|CSV files (*.csv)|*.csv|JSON files (*.json)|*.json" // + "|All files (*.*)|*.*"
});
if (saveFileDialog.ShowDialog() != DialogResult.OK)
if (Invoke(saveFileDialog.ShowDialog) != DialogResult.OK)
return;
// FilterIndex is 1-based, NOT 0-based
@ -141,13 +186,13 @@ namespace LibationWinForms.Dialogs
{
case 1: // xlsx
default:
RecordExporter.ToXlsx(saveFileDialog.FileName, records);
await Task.Run(() => RecordExporter.ToXlsx(saveFileDialog.FileName, records));
break;
case 2: // csv
RecordExporter.ToCsv(saveFileDialog.FileName, records);
await Task.Run(() => RecordExporter.ToCsv(saveFileDialog.FileName, records));
break;
case 3: // json
RecordExporter.ToJson(saveFileDialog.FileName, libraryBook, records);
await Task.Run(() => RecordExporter.ToJson(saveFileDialog.FileName, libraryBook, records));
break;
}
}
@ -163,7 +208,7 @@ namespace LibationWinForms.Dialogs
base.OnKeyDown(e);
}
#region dataGridView Bindings
#region DataGridView Bindings
private class BookRecordBindingList : BindingList<BookRecordEntry>
{

View file

@ -139,22 +139,22 @@ namespace LibationWinForms.GridView
var setDownloadMenuItem = new ToolStripMenuItem()
{
Text = "Set Download status to 'Downloaded'",
Text = "Set Download status to '&Downloaded'",
Enabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated
};
setDownloadMenuItem.Click += (_, __) => entry.Book.UpdateBookStatus(LiberatedStatus.Liberated);
var setNotDownloadMenuItem = new ToolStripMenuItem()
{
Text = "Set Download status to 'Not Downloaded'",
Text = "Set Download status to '&Not Downloaded'",
Enabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated
};
setNotDownloadMenuItem.Click += (_, __) => entry.Book.UpdateBookStatus(LiberatedStatus.NotLiberated);
var removeMenuItem = new ToolStripMenuItem() { Text = "Remove from library" };
var removeMenuItem = new ToolStripMenuItem() { Text = "&Remove from library" };
removeMenuItem.Click += (_, __) => LibraryCommands.RemoveBook(entry.AudibleProductId);
var locateFileMenuItem = new ToolStripMenuItem() { Text = "Locate file..." };
var locateFileMenuItem = new ToolStripMenuItem() { Text = "&Locate file..." };
locateFileMenuItem.Click += (_, __) =>
{
try
@ -175,7 +175,7 @@ namespace LibationWinForms.GridView
}
};
var bookRecordMenuItem = new ToolStripMenuItem { Text = "View Bookmarks/Clips" };
var bookRecordMenuItem = new ToolStripMenuItem { Text = "View &Bookmarks/Clips" };
bookRecordMenuItem.Click += (_, _) => new BookRecordsDialog(entry.LibraryBook).ShowDialog(this);
var stopLightContextMenu = new ContextMenuStrip();