* #396 New feature : match download status to files

* UI: Visible Books \> Set 'Downloaded' status automatically. Visible books. Prompts before saving changes
  * CLI: Full library. No prompt
This commit is contained in:
Robert McRackan 2022-12-06 14:58:22 -05:00
parent a54516b4f5
commit c4cebbebe7
23 changed files with 1071 additions and 604 deletions

View File

@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Version>8.5.1.1</Version>
<Version>8.6.0.1</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Octokit" Version="4.0.1" />

View File

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DataLayer;
using Dinah.Core;
using LibationFileManager;
namespace ApplicationServices
{
public class BulkSetDownloadStatus
{
private List<(string message, LiberatedStatus newStatus, IEnumerable<Book> Books)> actionSets { get; } = new();
public int Count => actionSets.Count;
public IEnumerable<string> Messages => actionSets.Select(a => a.message);
public string AggregateMessage => $"Are you sure you want to set {Messages.Aggregate((a, b) => $"{a} and {b}")}?";
private List<LibraryBook> _libraryBooks;
private bool _setDownloaded;
private bool _setNotDownloaded;
public BulkSetDownloadStatus(List<LibraryBook> libraryBooks, bool setDownloaded, bool setNotDownloaded)
{
_libraryBooks = libraryBooks;
_setDownloaded = setDownloaded;
_setNotDownloaded = setNotDownloaded;
}
public int Discover()
{
var bookExistsList = _libraryBooks
.Select(libraryBook => new
{
libraryBook.Book,
FileExists = AudibleFileStorage.Audio.GetPath(libraryBook.Book.AudibleProductId) is not null
})
.ToList();
if (_setDownloaded)
{
var books2change = bookExistsList
.Where(a => a.FileExists && a.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated)
.Select(a => a.Book)
.ToList();
if (books2change.Any())
actionSets.Add((
$"{"book".PluralizeWithCount(books2change.Count)} to 'Downloaded'",
LiberatedStatus.Liberated,
books2change));
}
if (_setNotDownloaded)
{
var books2change = bookExistsList
.Where(a => !a.FileExists && a.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated)
.Select(a => a.Book)
.ToList();
if (books2change.Any())
actionSets.Add((
$"{"book".PluralizeWithCount(books2change.Count)} to 'Not Downloaded'",
LiberatedStatus.NotLiberated,
books2change));
}
return Count;
}
public void Execute()
{
foreach (var a in actionSets)
a.Books.UpdateBookStatus(a.newStatus);
}
}
}

View File

@ -9,6 +9,7 @@ using Dinah.Core;
using DtoImporterService;
using LibationFileManager;
using Serilog;
using static System.Reflection.Metadata.BlobBuilder;
using static DtoImporterService.PerfLogger;
namespace ApplicationServices
@ -366,52 +367,79 @@ namespace ApplicationServices
public static event EventHandler<IEnumerable<Book>> BookUserDefinedItemCommitted;
#region Update book details
public static int UpdateBookStatus(this Book book, LiberatedStatus bookStatus)
{
book.UserDefinedItem.BookStatus = bookStatus;
return UpdateUserDefinedItem(book);
}
public static int UpdatePdfStatus(this Book book, LiberatedStatus pdfStatus)
{
book.UserDefinedItem.PdfStatus = pdfStatus;
return UpdateUserDefinedItem(book);
}
public static int UpdateBook(
public static int UpdateUserDefinedItem(
this Book book,
string tags = null,
LiberatedStatus? bookStatus = null,
LiberatedStatus? pdfStatus = null)
=> UpdateBooks(tags, bookStatus, pdfStatus, book);
public static int UpdateBooks(
=> new[] { book }.UpdateUserDefinedItem(tags, bookStatus, pdfStatus);
public static int UpdateUserDefinedItem(
this IEnumerable<Book> books,
string tags = null,
LiberatedStatus? bookStatus = null,
LiberatedStatus? pdfStatus = null,
params Book[] books)
{
foreach (var book in books)
{
LiberatedStatus? pdfStatus = null)
=> updateUserDefinedItem(
books,
udi => {
// blank tags are expected. null tags are not
if (tags is not null && book.UserDefinedItem.Tags != tags)
book.UserDefinedItem.Tags = tags;
if (tags is not null && udi.Tags != tags)
udi.Tags = tags;
if (bookStatus is not null && book.UserDefinedItem.BookStatus != bookStatus.Value)
book.UserDefinedItem.BookStatus = bookStatus.Value;
if (bookStatus is not null && udi.BookStatus != bookStatus.Value)
udi.BookStatus = bookStatus.Value;
// even though PdfStatus is nullable, there's no case where we'd actually overwrite with null
if (pdfStatus is not null && book.UserDefinedItem.PdfStatus != pdfStatus.Value)
book.UserDefinedItem.PdfStatus = pdfStatus.Value;
}
if (pdfStatus is not null && udi.PdfStatus != pdfStatus.Value)
udi.PdfStatus = pdfStatus.Value;
});
return UpdateUserDefinedItem(books);
}
public static int UpdateUserDefinedItem(params Book[] books) => UpdateUserDefinedItem(books.ToList());
public static int UpdateUserDefinedItem(IEnumerable<Book> books)
public static int UpdateBookStatus(this Book book, LiberatedStatus bookStatus)
=> book.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus);
public static int UpdateBookStatus(this IEnumerable<Book> books, LiberatedStatus bookStatus)
=> books.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus);
public static int UpdateBookStatus(this LibraryBook libraryBook, LiberatedStatus bookStatus)
=> libraryBook.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus);
public static int UpdateBookStatus(this IEnumerable<LibraryBook> libraryBooks, LiberatedStatus bookStatus)
=> libraryBooks.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus);
public static int UpdatePdfStatus(this Book book, LiberatedStatus pdfStatus)
=> book.UpdateUserDefinedItem(udi => udi.PdfStatus = pdfStatus);
public static int UpdatePdfStatus(this IEnumerable<Book> books, LiberatedStatus pdfStatus)
=> books.UpdateUserDefinedItem(udi => udi.PdfStatus = pdfStatus);
public static int UpdatePdfStatus(this LibraryBook libraryBook, LiberatedStatus pdfStatus)
=> libraryBook.UpdateUserDefinedItem(udi => udi.PdfStatus = pdfStatus);
public static int UpdatePdfStatus(this IEnumerable<LibraryBook> libraryBooks, LiberatedStatus pdfStatus)
=> libraryBooks.UpdateUserDefinedItem(udi => udi.PdfStatus = pdfStatus);
public static int UpdateTags(this Book book, string tags)
=> book.UpdateUserDefinedItem(udi => udi.Tags = tags);
public static int UpdateTags(this IEnumerable<Book> books, string tags)
=> books.UpdateUserDefinedItem(udi => udi.Tags = tags);
public static int UpdateTags(this LibraryBook libraryBook, string tags)
=> libraryBook.UpdateUserDefinedItem(udi => udi.Tags = tags);
public static int UpdateTags(this IEnumerable<LibraryBook> libraryBooks, string tags)
=> libraryBooks.UpdateUserDefinedItem(udi => udi.Tags = tags);
public static int UpdateUserDefinedItem(this LibraryBook libraryBook, Action<UserDefinedItem> action)
=> libraryBook.Book.updateUserDefinedItem(action);
public static int UpdateUserDefinedItem(this IEnumerable<LibraryBook> libraryBooks, Action<UserDefinedItem> action)
=> libraryBooks.Select(lb => lb.Book).updateUserDefinedItem(action);
public static int UpdateUserDefinedItem(this Book book, Action<UserDefinedItem> action) => book.updateUserDefinedItem(action);
public static int UpdateUserDefinedItem(this IEnumerable<Book> books, Action<UserDefinedItem> action) => books.updateUserDefinedItem(action);
private static int updateUserDefinedItem(this Book book, Action<UserDefinedItem> action) => new[] { book }.updateUserDefinedItem(action);
private static int updateUserDefinedItem(this IEnumerable<Book> books, Action<UserDefinedItem> action)
{
try
{
if (books is null || !books.Any())
return 0;
foreach (var book in books)
action?.Invoke(book.UserDefinedItem);
using var context = DbContexts.GetContext();
// Attach() NoTracking entities before SaveChanges()

View File

@ -50,7 +50,7 @@ namespace LibationAvalonia.Dialogs
protected override void SaveAndClose()
{
LibraryBook.Book.UpdateBook(NewTags, bookStatus: BookLiberatedStatus, pdfStatus: PdfLiberatedStatus);
LibraryBook.Book.UpdateUserDefinedItem(NewTags, bookStatus: BookLiberatedStatus, pdfStatus: PdfLiberatedStatus);
base.SaveAndClose();
}

View File

@ -0,0 +1,53 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="120"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchAutoDialog"
Title="Liberated status: Whether the book has been downloaded"
MinHeight="100" MaxHeight="165"
MinWidth="600" MaxWidth="800"
WindowStartupLocation="CenterOwner"
Icon="/Assets/libation.ico">
<Grid RowDefinitions="Auto,Auto,Auto">
<StackPanel
Grid.Row="0"
Orientation="Horizontal">
<CheckBox
Margin="0,0,0,10"
IsChecked="{Binding SetDownloaded, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="If the audio file can be found, set download status to 'Downloaded'" />
</CheckBox>
</StackPanel>
<StackPanel
Grid.Row="1"
Orientation="Horizontal">
<CheckBox
Margin="0,0,0,10"
IsChecked="{Binding SetNotDownloaded, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="If the audio file cannot be found, set download status to 'Not Downloaded'" />
</CheckBox>
</StackPanel>
<Button
Grid.Row="2"
Padding="30,0,30,0"
Margin="10,0,10,10"
HorizontalAlignment="Right"
Height="25"
Content="Save"
Click="SaveButton_Clicked"/>
</Grid>
</Window>

View File

@ -0,0 +1,23 @@
using Avalonia.Markup.Xaml;
namespace LibationAvalonia.Dialogs
{
public partial class LiberatedStatusBatchAutoDialog : DialogWindow
{
public bool SetDownloaded { get; set; }
public bool SetNotDownloaded { get; set; }
public LiberatedStatusBatchAutoDialog()
{
InitializeComponent();
DataContext = this;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> SaveAndClose();
}
}

View File

@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="120"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchDialog"
x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchManualDialog"
Title="Liberated status: Whether the book has been downloaded"
MinWidth="400" MinHeight="120"
MaxWidth="400" MaxHeight="120"

View File

@ -5,7 +5,7 @@ using System.Collections.Generic;
namespace LibationAvalonia.Dialogs
{
public partial class LiberatedStatusBatchDialog : DialogWindow
public partial class LiberatedStatusBatchManualDialog : DialogWindow
{
private class liberatedComboBoxItem
{
@ -34,7 +34,7 @@ namespace LibationAvalonia.Dialogs
new liberatedComboBoxItem { Status = LiberatedStatus.NotLiberated, Text = "Not Downloaded" },
};
public LiberatedStatusBatchDialog()
public LiberatedStatusBatchManualDialog()
{
InitializeComponent();
SelectedItem = BookStatuses[0] as liberatedComboBoxItem;

View File

@ -92,6 +92,12 @@
</ItemGroup>
<ItemGroup>
<Compile Update="Dialogs\LiberatedStatusBatchAutoDialog.axaml.cs">
<DependentUpon>LiberatedStatusBatchAutoDialog.axaml</DependentUpon>
</Compile>
<Compile Update="Dialogs\LiberatedStatusBatchManualDialog.axaml.cs">
<DependentUpon>LiberatedStatusBatchManualDialog.axaml</DependentUpon>
</Compile>
<Compile Update="Views\ProcessBookControl.axaml.cs">
<DependentUpon>ProcessBookControl.axaml</DependentUpon>
</Compile>

View File

@ -1,6 +1,8 @@
using ApplicationServices;
using Avalonia.Threading;
using DataLayer;
using Dinah.Core;
using LibationFileManager;
using System;
using System.Linq;
using System.Threading.Tasks;
@ -57,14 +59,12 @@ namespace LibationAvalonia.Views
if (confirmationResult != DialogResult.Yes)
return;
foreach (var libraryBook in visibleLibraryBooks)
libraryBook.Book.UserDefinedItem.Tags = dialog.NewTags;
LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book));
visibleLibraryBooks.UpdateTags(dialog.NewTags);
}
public async void setDownloadedToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
public async void setDownloadedManualToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
{
var dialog = new Dialogs.LiberatedStatusBatchDialog();
var dialog = new Dialogs.LiberatedStatusBatchManualDialog();
var result = await dialog.ShowDialog<DialogResult>(this);
if (result != DialogResult.OK)
return;
@ -81,9 +81,33 @@ namespace LibationAvalonia.Views
if (confirmationResult != DialogResult.Yes)
return;
foreach (var libraryBook in visibleLibraryBooks)
libraryBook.Book.UserDefinedItem.BookStatus = dialog.BookLiberatedStatus;
LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book));
visibleLibraryBooks.UpdateBookStatus(dialog.BookLiberatedStatus);
}
public async void setDownloadedAutoToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
{
var dialog = new Dialogs.LiberatedStatusBatchAutoDialog();
var result = await dialog.ShowDialog<DialogResult>(this);
if (result != DialogResult.OK)
return;
var bulkSetStatus = new BulkSetDownloadStatus(_viewModel.ProductsDisplay.GetVisibleBookEntries(), dialog.SetDownloaded, dialog.SetNotDownloaded);
var count = await Task.Run(() => bulkSetStatus.Discover());
if (count == 0)
return;
var confirmationResult = await MessageBox.Show(
bulkSetStatus.AggregateMessage,
"Replace downloaded status?",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1);
if (confirmationResult != DialogResult.Yes)
return;
bulkSetStatus.Execute();
}
public async void removeToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)

View File

@ -110,7 +110,8 @@
</MenuItem.Styles>
<MenuItem Click="liberateVisible" Header="{Binding LiberateVisibleToolStripText_2}" IsEnabled="{Binding AnyVisibleNotLiberated}" />
<MenuItem Click="replaceTagsToolStripMenuItem_Click" Header="Replace _Tags..." />
<MenuItem Click="setDownloadedToolStripMenuItem_Click" Header="Set '_Downloaded' status..." />
<MenuItem Click="setDownloadedManualToolStripMenuItem_Click" Header="Set '_Downloaded' status manually..." />
<MenuItem Click="setDownloadedAutoToolStripMenuItem_Click" Header="Set '_Downloaded' status automatically..." />
<MenuItem Click="removeToolStripMenuItem_Click" Header="_Remove from library..." />
</MenuItem>

View File

@ -8,7 +8,7 @@ using CommandLine;
namespace LibationCli
{
[Verb("export", HelpText = "Must include path and flag for export file type: --xlsx , --csv , --json]")]
[Verb("export", HelpText = "Must include path and flag for export file type: --xlsx , --csv , --json")]
public class ExportOptions : OptionsBase
{
[Option(shortName: 'p', longName: "path", Required = true, HelpText = "Path to save file to.")]

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ApplicationServices;
using AudibleUtilities;
using CommandLine;
namespace LibationCli
{
[Verb("set-status", HelpText = """
Set download statuses throughout library based on whether each book's audio file can be found.
Must include at least one flag: --downloaded , --not-downloaded.
Downloaded: If the audio file can be found, set download status to 'Downloaded'.
Not Downloaded: If the audio file cannot be found, set download status to 'Not Downloaded'
""")]
public class SetDownloadStatusOptions : OptionsBase
{
[Option(shortName: 'd', longName: "downloaded", Required = true)]
public bool SetDownloaded { get; set; }
[Option(shortName: 'n', longName: "not-downloaded", Required = true)]
public bool SetNotDownloaded { get; set; }
protected override async Task ProcessAsync()
{
var libraryBooks = DbContexts.GetLibrary_Flat_NoTracking();
var bulkSetStatus = new BulkSetDownloadStatus(libraryBooks, SetDownloaded, SetNotDownloaded);
await Task.Run(() => bulkSetStatus.Discover());
bulkSetStatus.Execute();
foreach (var msg in bulkSetStatus.Messages)
Console.WriteLine(msg);
}
}
}

View File

@ -113,6 +113,5 @@ namespace LibationFileManager
public void Refresh() => BookDirectoryFiles.RefreshFiles();
public LongPath GetPath(string productId) => GetFilePath(productId);
}
}

View File

@ -0,0 +1,108 @@
namespace LibationWinForms.Dialogs
{
partial class LiberatedStatusBatchAutoDialog
{
/// <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()
{
this.setDownloadedCb = new System.Windows.Forms.CheckBox();
this.setNotDownloadedCb = new System.Windows.Forms.CheckBox();
this.okBtn = new System.Windows.Forms.Button();
this.cancelBtn = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// setDownloadedCb
//
this.setDownloadedCb.AutoSize = true;
this.setDownloadedCb.Location = new System.Drawing.Point(12, 12);
this.setDownloadedCb.Name = "setDownloadedCb";
this.setDownloadedCb.Size = new System.Drawing.Size(379, 19);
this.setDownloadedCb.TabIndex = 0;
this.setDownloadedCb.Text = "If the audio file can be found, set download status to \'Downloaded\'";
this.setDownloadedCb.UseVisualStyleBackColor = true;
//
// setNotDownloadedCb
//
this.setNotDownloadedCb.AutoSize = true;
this.setNotDownloadedCb.Location = new System.Drawing.Point(12, 37);
this.setNotDownloadedCb.Name = "setNotDownloadedCb";
this.setNotDownloadedCb.Size = new System.Drawing.Size(412, 19);
this.setNotDownloadedCb.TabIndex = 1;
this.setNotDownloadedCb.Text = "If the audio file cannot be found, set download status to \'Not Downloaded\'";
this.setNotDownloadedCb.UseVisualStyleBackColor = true;
//
// okBtn
//
this.okBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.okBtn.Location = new System.Drawing.Point(346, 79);
this.okBtn.Name = "okBtn";
this.okBtn.Size = new System.Drawing.Size(88, 27);
this.okBtn.TabIndex = 2;
this.okBtn.Text = "OK";
this.okBtn.UseVisualStyleBackColor = true;
this.okBtn.Click += new System.EventHandler(this.okBtn_Click);
//
// cancelBtn
//
this.cancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.cancelBtn.Location = new System.Drawing.Point(464, 79);
this.cancelBtn.Name = "cancelBtn";
this.cancelBtn.Size = new System.Drawing.Size(88, 27);
this.cancelBtn.TabIndex = 3;
this.cancelBtn.Text = "Cancel";
this.cancelBtn.UseVisualStyleBackColor = true;
//
// LiberatedStatusBatchAutoDialog
//
this.AcceptButton = this.okBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelBtn;
this.ClientSize = new System.Drawing.Size(564, 118);
this.Controls.Add(this.cancelBtn);
this.Controls.Add(this.okBtn);
this.Controls.Add(this.setNotDownloadedCb);
this.Controls.Add(this.setDownloadedCb);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "LiberatedStatusBatchAutoDialog";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Liberated status: Scan for files";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.CheckBox setDownloadedCb;
private System.Windows.Forms.CheckBox setNotDownloadedCb;
private System.Windows.Forms.Button okBtn;
private System.Windows.Forms.Button cancelBtn;
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Windows.Forms;
namespace LibationWinForms.Dialogs
{
public partial class LiberatedStatusBatchAutoDialog : Form
{
public bool SetDownloaded { get; private set; }
public bool SetNotDownloaded { get; private set; }
public LiberatedStatusBatchAutoDialog()
{
InitializeComponent();
this.SetLibationIcon();
}
private void okBtn_Click(object sender, EventArgs e)
{
SetDownloaded = this.setDownloadedCb.Checked;
SetNotDownloaded = this.setNotDownloadedCb.Checked;
this.DialogResult = DialogResult.OK;
}
}
}

View File

@ -1,6 +1,6 @@
namespace LibationWinForms.Dialogs
{
partial class LiberatedStatusBatchDialog
partial class LiberatedStatusBatchManualDialog
{
/// <summary>
/// Required designer variable.
@ -72,7 +72,6 @@
this.cancelBtn.TabIndex = 9;
this.cancelBtn.Text = "Cancel";
this.cancelBtn.UseVisualStyleBackColor = true;
this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click);
//
// saveBtn
//
@ -86,7 +85,7 @@
this.saveBtn.UseVisualStyleBackColor = true;
this.saveBtn.Click += new System.EventHandler(this.saveBtn_Click);
//
// LiberatedStatusBatchDialog
// LiberatedStatusBatchManualDialog
//
this.AcceptButton = this.saveBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
@ -101,7 +100,7 @@
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "LiberatedStatusBatchDialog";
this.Name = "LiberatedStatusBatchManualDialog";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Liberated status: Whether the book has been downloaded";

View File

@ -8,7 +8,7 @@ using LibationFileManager;
namespace LibationWinForms.Dialogs
{
public partial class LiberatedStatusBatchDialog : Form
public partial class LiberatedStatusBatchManualDialog : Form
{
public LiberatedStatus BookLiberatedStatus { get; private set; }
@ -19,7 +19,7 @@ namespace LibationWinForms.Dialogs
public override string ToString() => Text;
}
public LiberatedStatusBatchDialog()
public LiberatedStatusBatchManualDialog()
{
InitializeComponent();
this.SetLibationIcon();
@ -35,11 +35,5 @@ namespace LibationWinForms.Dialogs
BookLiberatedStatus = ((liberatedComboBoxItem)this.bookLiberatedCb.SelectedItem).Status;
this.DialogResult = DialogResult.OK;
}
private void cancelBtn_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
}
}
}

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>

View File

@ -57,7 +57,7 @@
this.visibleBooksToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
this.liberateVisibleToolStripMenuItem_VisibleBooksMenu = new LibationWinForms.FormattableToolStripMenuItem();
this.replaceTagsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.setDownloadedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.setDownloadedManualToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.accountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@ -77,6 +77,7 @@
this.doneRemovingBtn = new System.Windows.Forms.Button();
this.removeBooksBtn = new System.Windows.Forms.Button();
this.processBookQueue1 = new LibationWinForms.ProcessQueue.ProcessQueueControl();
this.setDownloadedAutoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
@ -315,7 +316,8 @@
this.visibleBooksToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.liberateVisibleToolStripMenuItem_VisibleBooksMenu,
this.replaceTagsToolStripMenuItem,
this.setDownloadedToolStripMenuItem,
this.setDownloadedManualToolStripMenuItem,
this.setDownloadedAutoToolStripMenuItem,
this.removeToolStripMenuItem});
this.visibleBooksToolStripMenuItem.FormatText = "&Visible Books: {0}";
this.visibleBooksToolStripMenuItem.Name = "visibleBooksToolStripMenuItem";
@ -326,28 +328,28 @@
//
this.liberateVisibleToolStripMenuItem_VisibleBooksMenu.FormatText = "&Liberate: {0}";
this.liberateVisibleToolStripMenuItem_VisibleBooksMenu.Name = "liberateVisibleToolStripMenuItem_VisibleBooksMenu";
this.liberateVisibleToolStripMenuItem_VisibleBooksMenu.Size = new System.Drawing.Size(209, 22);
this.liberateVisibleToolStripMenuItem_VisibleBooksMenu.Size = new System.Drawing.Size(284, 22);
this.liberateVisibleToolStripMenuItem_VisibleBooksMenu.Text = "&Liberate: {0}";
this.liberateVisibleToolStripMenuItem_VisibleBooksMenu.Click += new System.EventHandler(this.liberateVisible);
//
// replaceTagsToolStripMenuItem
//
this.replaceTagsToolStripMenuItem.Name = "replaceTagsToolStripMenuItem";
this.replaceTagsToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
this.replaceTagsToolStripMenuItem.Size = new System.Drawing.Size(284, 22);
this.replaceTagsToolStripMenuItem.Text = "Replace &Tags...";
this.replaceTagsToolStripMenuItem.Click += new System.EventHandler(this.replaceTagsToolStripMenuItem_Click);
//
// setDownloadedToolStripMenuItem
// setDownloadedManualToolStripMenuItem
//
this.setDownloadedToolStripMenuItem.Name = "setDownloadedToolStripMenuItem";
this.setDownloadedToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
this.setDownloadedToolStripMenuItem.Text = "Set \'&Downloaded\' status...";
this.setDownloadedToolStripMenuItem.Click += new System.EventHandler(this.setDownloadedToolStripMenuItem_Click);
this.setDownloadedManualToolStripMenuItem.Name = "setDownloadedManualToolStripMenuItem";
this.setDownloadedManualToolStripMenuItem.Size = new System.Drawing.Size(284, 22);
this.setDownloadedManualToolStripMenuItem.Text = "Set \'&Downloaded\' status manually...";
this.setDownloadedManualToolStripMenuItem.Click += new System.EventHandler(this.setDownloadedManualToolStripMenuItem_Click);
//
// removeToolStripMenuItem
//
this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
this.removeToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
this.removeToolStripMenuItem.Size = new System.Drawing.Size(284, 22);
this.removeToolStripMenuItem.Text = "&Remove from library...";
this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click);
//
@ -400,7 +402,7 @@
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 16, 0);
this.statusStrip1.ShowItemToolTips = true;
this.statusStrip1.Size = new System.Drawing.Size(1037, 22);
this.statusStrip1.Size = new System.Drawing.Size(1033, 22);
this.statusStrip1.TabIndex = 6;
this.statusStrip1.Text = "statusStrip1";
//
@ -414,7 +416,7 @@
// springLbl
//
this.springLbl.Name = "springLbl";
this.springLbl.Size = new System.Drawing.Size(523, 17);
this.springLbl.Size = new System.Drawing.Size(519, 17);
this.springLbl.Spring = true;
//
// backupsCountsLbl
@ -458,7 +460,7 @@
//
this.splitContainer1.Panel2.Controls.Add(this.processBookQueue1);
this.splitContainer1.Size = new System.Drawing.Size(1463, 640);
this.splitContainer1.SplitterDistance = 1037;
this.splitContainer1.SplitterDistance = 1033;
this.splitContainer1.SplitterWidth = 8;
this.splitContainer1.TabIndex = 7;
//
@ -477,7 +479,7 @@
this.panel1.Location = new System.Drawing.Point(0, 24);
this.panel1.Margin = new System.Windows.Forms.Padding(0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(1037, 594);
this.panel1.Size = new System.Drawing.Size(1033, 594);
this.panel1.TabIndex = 7;
//
// productsDisplay
@ -499,7 +501,7 @@
// toggleQueueHideBtn
//
this.toggleQueueHideBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.toggleQueueHideBtn.Location = new System.Drawing.Point(989, 3);
this.toggleQueueHideBtn.Location = new System.Drawing.Point(985, 3);
this.toggleQueueHideBtn.Margin = new System.Windows.Forms.Padding(4, 3, 15, 3);
this.toggleQueueHideBtn.Name = "toggleQueueHideBtn";
this.toggleQueueHideBtn.Size = new System.Drawing.Size(33, 27);
@ -540,9 +542,16 @@
this.processBookQueue1.Location = new System.Drawing.Point(0, 0);
this.processBookQueue1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.processBookQueue1.Name = "processBookQueue1";
this.processBookQueue1.Size = new System.Drawing.Size(418, 640);
this.processBookQueue1.Size = new System.Drawing.Size(422, 640);
this.processBookQueue1.TabIndex = 0;
//
// setDownloadedAutoToolStripMenuItem
//
this.setDownloadedAutoToolStripMenuItem.Name = "setDownloadedAutoToolStripMenuItem";
this.setDownloadedAutoToolStripMenuItem.Size = new System.Drawing.Size(284, 22);
this.setDownloadedAutoToolStripMenuItem.Text = "Set \'&Downloaded\' status automatically...";
this.setDownloadedAutoToolStripMenuItem.Click += new System.EventHandler(this.setDownloadedAutoToolStripMenuItem_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
@ -609,7 +618,8 @@
private LibationWinForms.FormattableToolStripMenuItem visibleBooksToolStripMenuItem;
private LibationWinForms.FormattableToolStripMenuItem liberateVisibleToolStripMenuItem_VisibleBooksMenu;
private System.Windows.Forms.ToolStripMenuItem replaceTagsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem setDownloadedToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem setDownloadedManualToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem setDownloadedAutoToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem;
private LibationWinForms.FormattableToolStripMenuItem liberateVisibleToolStripMenuItem_LiberateMenu;
private System.Windows.Forms.SplitContainer splitContainer1;

View File

@ -87,14 +87,12 @@ namespace LibationWinForms
if (confirmationResult != DialogResult.Yes)
return;
foreach (var libraryBook in visibleLibraryBooks)
libraryBook.Book.UserDefinedItem.Tags = dialog.NewTags;
LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book));
visibleLibraryBooks.UpdateTags(dialog.NewTags);
}
private void setDownloadedToolStripMenuItem_Click(object sender, EventArgs e)
private void setDownloadedManualToolStripMenuItem_Click(object sender, EventArgs e)
{
var dialog = new LiberatedStatusBatchDialog();
var dialog = new LiberatedStatusBatchManualDialog();
var result = dialog.ShowDialog();
if (result != DialogResult.OK)
return;
@ -110,9 +108,33 @@ namespace LibationWinForms
if (confirmationResult != DialogResult.Yes)
return;
foreach (var libraryBook in visibleLibraryBooks)
libraryBook.Book.UserDefinedItem.BookStatus = dialog.BookLiberatedStatus;
LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book));
visibleLibraryBooks.UpdateBookStatus(dialog.BookLiberatedStatus);
}
private async void setDownloadedAutoToolStripMenuItem_Click(object sender, EventArgs e)
{
var dialog = new LiberatedStatusBatchAutoDialog();
var result = dialog.ShowDialog();
if (result != DialogResult.OK)
return;
var bulkSetStatus = new BulkSetDownloadStatus(productsDisplay.GetVisible(), dialog.SetDownloaded, dialog.SetNotDownloaded);
var count = await Task.Run(() => bulkSetStatus.Discover());
if (count == 0)
return;
var confirmationResult = MessageBox.Show(
bulkSetStatus.AggregateMessage,
"Replace downloaded status?",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1);
if (confirmationResult != DialogResult.Yes)
return;
bulkSetStatus.Execute();
}
private async void removeToolStripMenuItem_Click(object sender, EventArgs e)

View File

@ -128,7 +128,7 @@ namespace LibationWinForms.GridView
/// <summary>Save edits to the database</summary>
public void Commit(string newTags, LiberatedStatus bookStatus, LiberatedStatus? pdfStatus)
// MVVM pass-through
=> Book.UpdateBook(newTags, bookStatus: bookStatus, pdfStatus: pdfStatus);
=> Book.UpdateUserDefinedItem(newTags, bookStatus: bookStatus, pdfStatus: pdfStatus);
#endregion