From 7eaa03e43cfeeb2bde3b228e21ff2119e9e2aa0c Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Thu, 5 Jan 2023 23:40:39 -0700 Subject: [PATCH] Add clip and bookmark viewer and exporter --- Source/ApplicationServices/RecordExporter.cs | 85 +++++-- .../AudibleUtilities/AudibleUtilities.csproj | 2 +- .../Controls/DataGridContextMenus.cs | 6 +- .../Dialogs/BookRecordsDialog.axaml | 139 +++++++++++ .../Dialogs/BookRecordsDialog.axaml.cs | 219 ++++++++++++++++++ .../Views/ProcessQueueControl.axaml | 2 +- .../Views/ProductsDisplay.axaml.cs | 10 +- .../Dialogs/BookRecordsDialog.Designer.cs | 27 ++- .../Dialogs/BookRecordsDialog.cs | 81 +++++-- .../LibationWinForms/GridView/ProductsGrid.cs | 10 +- 10 files changed, 529 insertions(+), 52 deletions(-) create mode 100644 Source/LibationAvalonia/Dialogs/BookRecordsDialog.axaml create mode 100644 Source/LibationAvalonia/Dialogs/BookRecordsDialog.axaml.cs diff --git a/Source/ApplicationServices/RecordExporter.cs b/Source/ApplicationServices/RecordExporter.cs index bddb1e36..44101738 100644 --- a/Source/ApplicationServices/RecordExporter.cs +++ b/Source/ApplicationServices/RecordExporter.cs @@ -31,7 +31,7 @@ namespace ApplicationServices var columns = new List { - nameof(IRecord.RecordType), + nameof(Type.Name), nameof(IRecord.Created), nameof(IRecord.Start) + "_ms", }; @@ -68,7 +68,7 @@ namespace ApplicationServices row = sheet.CreateRow(++rowIndex); - row.CreateCell(col++).SetCellValue(record.RecordType); + row.CreateCell(col++).SetCellValue(record.GetType().Name); var dateCreatedCell = row.CreateCell(col++); dateCreatedCell.CellStyle = dateStyle; @@ -104,16 +104,18 @@ namespace ApplicationServices if (!records.Any()) return; + var recordsEx = extendRecords(records); + var recordsObj = new JObject { { "title", libraryBook.Book.Title}, { "asin", libraryBook.Book.AudibleProductId}, { "exportTime", DateTime.Now}, - { "records", JArray.FromObject(records) } + { "records", JArray.FromObject(recordsEx) } }; System.IO.File.WriteAllText(saveFilePath, recordsObj.ToString(Newtonsoft.Json.Formatting.Indented)); - } + } public static void ToCsv(string saveFilePath, IEnumerable records) { @@ -123,21 +125,74 @@ namespace ApplicationServices using var writer = new System.IO.StreamWriter(saveFilePath); using var csv = new CsvWriter(writer, System.Globalization.CultureInfo.CurrentCulture); - //Write headers for the present type that has the most properties + //Write headers for the present record type that has the most properties if (records.OfType().Any()) - csv.WriteHeader(typeof(Clip)); - else if (records.OfType().Any()) - csv.WriteHeader(typeof(IRangeAnnotation)); - else if (records.OfType().Any()) - csv.WriteHeader(typeof(IAnnotation)); + csv.WriteHeader(typeof(ClipEx)); + else if (records.OfType().Any()) + csv.WriteHeader(typeof(NoteEx)); + else if (records.OfType().Any()) + csv.WriteHeader(typeof(BookmarkEx)); else - csv.WriteHeader(typeof(IRecord)); + csv.WriteHeader(typeof(LastHeardEx)); + + var recordsEx = extendRecords(records); csv.NextRecord(); - csv.WriteRecords(records.OfType()); - csv.WriteRecords(records.OfType()); - csv.WriteRecords(records.OfType()); - csv.WriteRecords(records.OfType()); + csv.WriteRecords(recordsEx.OfType()); + csv.WriteRecords(recordsEx.OfType()); + csv.WriteRecords(recordsEx.OfType()); + csv.WriteRecords(recordsEx.OfType()); + } + + private static IEnumerable extendRecords(IEnumerable records) + => records + .Select( + r => r switch + { + Clip c => new ClipEx(nameof(Clip), c), + Note n => new NoteEx(nameof(Note), n), + Bookmark b => new BookmarkEx(nameof(Bookmark), b), + LastHeard l => new LastHeardEx(nameof(LastHeard), l), + _ => throw new InvalidOperationException(), + }); + + + private interface IRecordEx { string Type { get; } } + + private record LastHeardEx : LastHeard, IRecordEx + { + public string Type { get; } + public LastHeardEx(string type, LastHeard original) : base(original) + { + Type = type; + } + } + + private record BookmarkEx : Bookmark, IRecordEx + { + public string Type { get; } + public BookmarkEx(string type, Bookmark original) : base(original) + { + Type = type; + } + } + + private record NoteEx : Note, IRecordEx + { + public string Type { get; } + public NoteEx(string type, Note original) : base(original) + { + Type = type; + } + } + + private record ClipEx : Clip, IRecordEx + { + public string Type { get; } + public ClipEx(string type, Clip original) : base(original) + { + Type = type; + } } } } diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index 50f6bdc0..326eefc1 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -5,7 +5,7 @@ - + diff --git a/Source/LibationAvalonia/Controls/DataGridContextMenus.cs b/Source/LibationAvalonia/Controls/DataGridContextMenus.cs index 4ec6d825..68660430 100644 --- a/Source/LibationAvalonia/Controls/DataGridContextMenus.cs +++ b/Source/LibationAvalonia/Controls/DataGridContextMenus.cs @@ -10,7 +10,7 @@ namespace LibationAvalonia.Controls { public static event EventHandler CellContextMenuStripNeeded; private static readonly ContextMenu ContextMenu = new(); - private static readonly AvaloniaList MenuItems = new(); + private static readonly AvaloniaList MenuItems = new(); private static readonly PropertyInfo OwningColumnProperty; static DataGridContextMenus() @@ -65,7 +65,7 @@ namespace LibationAvalonia.Controls public DataGridColumn Column { get; init; } public GridEntry GridEntry { get; init; } public ContextMenu ContextMenu { get; init; } - public AvaloniaList ContextMenuItems - => ContextMenu.Items as AvaloniaList; + public AvaloniaList ContextMenuItems + => ContextMenu.Items as AvaloniaList; } } diff --git a/Source/LibationAvalonia/Dialogs/BookRecordsDialog.axaml b/Source/LibationAvalonia/Dialogs/BookRecordsDialog.axaml new file mode 100644 index 00000000..3cb749aa --- /dev/null +++ b/Source/LibationAvalonia/Dialogs/BookRecordsDialog.axaml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +