From bce3bdba7ed2f263284cc4be99537ce54b906fb7 Mon Sep 17 00:00:00 2001 From: Robert McRackan Date: Thu, 12 May 2022 11:57:56 -0400 Subject: [PATCH] Feature requests #229 , #148 : Bulk actions on filtered books --- Source/AppScaffolding/AppScaffolding.csproj | 2 +- .../LiberatedStatusBatchDialog.Designer.cs | 120 ++++++++++++++++++ .../Dialogs/LiberatedStatusBatchDialog.cs | 45 +++++++ .../Dialogs/LiberatedStatusBatchDialog.resx | 60 +++++++++ .../Dialogs/TagsBatchDialog.Designer.cs | 112 ++++++++++++++++ .../Dialogs/TagsBatchDialog.cs | 35 +++++ .../Dialogs/TagsBatchDialog.resx | 60 +++++++++ Source/LibationWinForms/Form1.cs | 61 ++++++--- 8 files changed, 475 insertions(+), 20 deletions(-) create mode 100644 Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.Designer.cs create mode 100644 Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.cs create mode 100644 Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.resx create mode 100644 Source/LibationWinForms/Dialogs/TagsBatchDialog.Designer.cs create mode 100644 Source/LibationWinForms/Dialogs/TagsBatchDialog.cs create mode 100644 Source/LibationWinForms/Dialogs/TagsBatchDialog.resx diff --git a/Source/AppScaffolding/AppScaffolding.csproj b/Source/AppScaffolding/AppScaffolding.csproj index c4ee9183..ad40a990 100644 --- a/Source/AppScaffolding/AppScaffolding.csproj +++ b/Source/AppScaffolding/AppScaffolding.csproj @@ -3,7 +3,7 @@ net6.0-windows - 7.4.0.1 + 7.5.0.1 diff --git a/Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.Designer.cs b/Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.Designer.cs new file mode 100644 index 00000000..7c51c134 --- /dev/null +++ b/Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.Designer.cs @@ -0,0 +1,120 @@ +namespace LibationWinForms.Dialogs +{ + partial class LiberatedStatusBatchDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.bookLiberatedCb = new System.Windows.Forms.ComboBox(); + this.bookLiberatedLbl = new System.Windows.Forms.Label(); + this.liberatedDescLbl = new System.Windows.Forms.Label(); + this.cancelBtn = new System.Windows.Forms.Button(); + this.saveBtn = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // bookLiberatedCb + // + this.bookLiberatedCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.bookLiberatedCb.FormattingEnabled = true; + this.bookLiberatedCb.Location = new System.Drawing.Point(52, 54); + this.bookLiberatedCb.Name = "bookLiberatedCb"; + this.bookLiberatedCb.Size = new System.Drawing.Size(121, 23); + this.bookLiberatedCb.TabIndex = 7; + // + // bookLiberatedLbl + // + this.bookLiberatedLbl.AutoSize = true; + this.bookLiberatedLbl.Location = new System.Drawing.Point(12, 57); + this.bookLiberatedLbl.Name = "bookLiberatedLbl"; + this.bookLiberatedLbl.Size = new System.Drawing.Size(34, 15); + this.bookLiberatedLbl.TabIndex = 6; + this.bookLiberatedLbl.Text = "Book"; + // + // liberatedDescLbl + // + this.liberatedDescLbl.AutoSize = true; + this.liberatedDescLbl.Location = new System.Drawing.Point(12, 9); + this.liberatedDescLbl.Name = "liberatedDescLbl"; + this.liberatedDescLbl.Size = new System.Drawing.Size(312, 30); + this.liberatedDescLbl.TabIndex = 5; + this.liberatedDescLbl.Text = "To download again next time: change to Not Downloaded\r\nTo not download: change to" + + " Downloaded"; + // + // 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 = 9; + this.cancelBtn.Text = "Cancel"; + this.cancelBtn.UseVisualStyleBackColor = true; + this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click); + // + // saveBtn + // + this.saveBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.saveBtn.Location = new System.Drawing.Point(346, 79); + this.saveBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.saveBtn.Name = "saveBtn"; + this.saveBtn.Size = new System.Drawing.Size(88, 27); + this.saveBtn.TabIndex = 8; + this.saveBtn.Text = "Save"; + this.saveBtn.UseVisualStyleBackColor = true; + this.saveBtn.Click += new System.EventHandler(this.saveBtn_Click); + // + // LiberatedStatusBatchDialog + // + this.AcceptButton = this.saveBtn; + 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.saveBtn); + this.Controls.Add(this.bookLiberatedCb); + this.Controls.Add(this.bookLiberatedLbl); + this.Controls.Add(this.liberatedDescLbl); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "LiberatedStatusBatchDialog"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Liberated status: Whether the book has been downloaded"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.ComboBox bookLiberatedCb; + private System.Windows.Forms.Label bookLiberatedLbl; + private System.Windows.Forms.Label liberatedDescLbl; + private System.Windows.Forms.Button cancelBtn; + private System.Windows.Forms.Button saveBtn; + } +} \ No newline at end of file diff --git a/Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.cs b/Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.cs new file mode 100644 index 00000000..ff3682f7 --- /dev/null +++ b/Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using DataLayer; +using Dinah.Core; +using LibationFileManager; + +namespace LibationWinForms.Dialogs +{ + public partial class LiberatedStatusBatchDialog : Form + { + public LiberatedStatus BookLiberatedStatus { get; private set; } + + public class liberatedComboBoxItem + { + public LiberatedStatus Status { get; set; } + public string Text { get; set; } + public override string ToString() => Text; + } + + public LiberatedStatusBatchDialog() + { + InitializeComponent(); + this.SetLibationIcon(); + + this.bookLiberatedCb.Items.Add(new liberatedComboBoxItem { Status = LiberatedStatus.Liberated, Text = "Downloaded" }); + this.bookLiberatedCb.Items.Add(new liberatedComboBoxItem { Status = LiberatedStatus.NotLiberated, Text = "Not Downloaded" }); + + this.bookLiberatedCb.SelectedIndex = 0; + } + + private void saveBtn_Click(object sender, EventArgs e) + { + BookLiberatedStatus = ((liberatedComboBoxItem)this.bookLiberatedCb.SelectedItem).Status; + this.DialogResult = DialogResult.OK; + } + + private void cancelBtn_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + } +} diff --git a/Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.resx b/Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.resx new file mode 100644 index 00000000..f298a7be --- /dev/null +++ b/Source/LibationWinForms/Dialogs/LiberatedStatusBatchDialog.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/LibationWinForms/Dialogs/TagsBatchDialog.Designer.cs b/Source/LibationWinForms/Dialogs/TagsBatchDialog.Designer.cs new file mode 100644 index 00000000..e0b73d59 --- /dev/null +++ b/Source/LibationWinForms/Dialogs/TagsBatchDialog.Designer.cs @@ -0,0 +1,112 @@ +namespace LibationWinForms.Dialogs +{ + partial class TagsBatchDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tagsDescLbl = new System.Windows.Forms.Label(); + this.newTagsTb = new System.Windows.Forms.TextBox(); + this.cancelBtn = new System.Windows.Forms.Button(); + this.saveBtn = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // tagsDescLbl + // + this.tagsDescLbl.AutoSize = true; + this.tagsDescLbl.Location = new System.Drawing.Point(13, 9); + this.tagsDescLbl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.tagsDescLbl.Name = "tagsDescLbl"; + this.tagsDescLbl.Size = new System.Drawing.Size(458, 15); + this.tagsDescLbl.TabIndex = 2; + this.tagsDescLbl.Text = "Tags are separated by a space. Each tag can contain letters, numbers, and undersc" + + "ores"; + // + // newTagsTb + // + this.newTagsTb.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.newTagsTb.Location = new System.Drawing.Point(13, 30); + this.newTagsTb.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.newTagsTb.Name = "newTagsTb"; + this.newTagsTb.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.newTagsTb.Size = new System.Drawing.Size(591, 23); + this.newTagsTb.TabIndex = 3; + // + // 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(517, 71); + this.cancelBtn.Name = "cancelBtn"; + this.cancelBtn.Size = new System.Drawing.Size(88, 27); + this.cancelBtn.TabIndex = 6; + this.cancelBtn.Text = "Cancel"; + this.cancelBtn.UseVisualStyleBackColor = true; + this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click); + // + // saveBtn + // + this.saveBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.saveBtn.Location = new System.Drawing.Point(399, 71); + this.saveBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.saveBtn.Name = "saveBtn"; + this.saveBtn.Size = new System.Drawing.Size(88, 27); + this.saveBtn.TabIndex = 5; + this.saveBtn.Text = "Save"; + this.saveBtn.UseVisualStyleBackColor = true; + this.saveBtn.Click += new System.EventHandler(this.saveBtn_Click); + // + // TagsBatchDialog + // + this.AcceptButton = this.saveBtn; + 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(617, 110); + this.Controls.Add(this.cancelBtn); + this.Controls.Add(this.saveBtn); + this.Controls.Add(this.tagsDescLbl); + this.Controls.Add(this.newTagsTb); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "TagsBatchDialog"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Replace Tags"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label tagsDescLbl; + private System.Windows.Forms.TextBox newTagsTb; + private System.Windows.Forms.Button cancelBtn; + private System.Windows.Forms.Button saveBtn; + } +} \ No newline at end of file diff --git a/Source/LibationWinForms/Dialogs/TagsBatchDialog.cs b/Source/LibationWinForms/Dialogs/TagsBatchDialog.cs new file mode 100644 index 00000000..bd74c532 --- /dev/null +++ b/Source/LibationWinForms/Dialogs/TagsBatchDialog.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace LibationWinForms.Dialogs +{ + public partial class TagsBatchDialog : Form + { + public string NewTags { get; private set; } + + public TagsBatchDialog() + { + InitializeComponent(); + this.SetLibationIcon(); + } + + private void saveBtn_Click(object sender, EventArgs e) + { + NewTags = this.newTagsTb.Text; + this.DialogResult = DialogResult.OK; + } + + private void cancelBtn_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + } +} diff --git a/Source/LibationWinForms/Dialogs/TagsBatchDialog.resx b/Source/LibationWinForms/Dialogs/TagsBatchDialog.resx new file mode 100644 index 00000000..f298a7be --- /dev/null +++ b/Source/LibationWinForms/Dialogs/TagsBatchDialog.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/LibationWinForms/Form1.cs b/Source/LibationWinForms/Form1.cs index ad278c35..a4abb1ed 100644 --- a/Source/LibationWinForms/Form1.cs +++ b/Source/LibationWinForms/Form1.cs @@ -52,7 +52,12 @@ public Form1() // independent UI updates this.Load += (_, _) => this.RestoreSizeAndLocation(Configuration.Instance); this.FormClosing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance); - LibraryCommands.LibrarySizeChanged += reloadGridAndUpdateBottomNumbers; + LibraryCommands.LibrarySizeChanged += (_, __) => + { + this.UIThreadSync(() => productsGrid.Display()); + this.UIThreadAsync(() => doFilter(lastGoodFilter)); + }; + LibraryCommands.LibrarySizeChanged += setBackupCounts; this.Load += setBackupCounts; LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts; QuickFilters.Updated += updateFiltersMenu; @@ -82,21 +87,11 @@ private void Form1_Load(object sender, EventArgs e) // I'm leaving this empty call here as a reminder that if we use this, it should probably be after DesignMode check } - private void reloadGridAndUpdateBottomNumbers(object _, object __) - { - this.UIThreadSync(() => productsGrid.Display()); - - // UI init complete. now we can apply filter - this.UIThreadAsync(() => doFilter(lastGoodFilter)); - - setBackupCounts(); - } - #region bottom: backup counts private System.ComponentModel.BackgroundWorker updateCountsBw; private bool runBackupCountsAgain; - private void setBackupCounts(object _ = null, object __ = null) + private void setBackupCounts(object _, object __) { runBackupCountsAgain = true; @@ -561,33 +556,61 @@ private async void liberateVisible(object sender, EventArgs e) private void replaceTagsToolStripMenuItem_Click(object sender, EventArgs e) { + var dialog = new TagsBatchDialog(); + var result = dialog.ShowDialog(); + if (result != DialogResult.OK) + return; + var visibleLibraryBooks = productsGrid.GetVisible(); + + var confirmationResult = MessageBoxLib.ShowConfirmationDialog( + visibleLibraryBooks, + $"Are you sure you want to replace tags in {0}?", + "Replace tags?"); + + if (confirmationResult != DialogResult.Yes) + return; + foreach (var libraryBook in visibleLibraryBooks) - libraryBook.Book.UserDefinedItem.Tags = "ggggg"; + libraryBook.Book.UserDefinedItem.Tags = dialog.NewTags; LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book)); } private void setDownloadedToolStripMenuItem_Click(object sender, EventArgs e) { + var dialog = new LiberatedStatusBatchDialog(); + var result = dialog.ShowDialog(); + if (result != DialogResult.OK) + return; + var visibleLibraryBooks = productsGrid.GetVisible(); + + var confirmationResult = MessageBoxLib.ShowConfirmationDialog( + visibleLibraryBooks, + $"Are you sure you want to replace downloaded status in {0}?", + "Replace downloaded status?"); + + if (confirmationResult != DialogResult.Yes) + return; + foreach (var libraryBook in visibleLibraryBooks) - libraryBook.Book.UserDefinedItem.BookStatus = DataLayer.LiberatedStatus.NotLiberated; + libraryBook.Book.UserDefinedItem.BookStatus = dialog.BookLiberatedStatus; LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book)); } private async void removeToolStripMenuItem_Click(object sender, EventArgs e) { - var libraryBooks = productsGrid.GetVisible(); + var visibleLibraryBooks = productsGrid.GetVisible(); - var result = MessageBoxLib.ShowConfirmationDialog( - libraryBooks, + var confirmationResult = MessageBoxLib.ShowConfirmationDialog( + visibleLibraryBooks, $"Are you sure you want to remove {0} from Libation's library?", "Remove books from Libation?"); - if (result != DialogResult.Yes) + if (confirmationResult != DialogResult.Yes) return; - var visibleIds = libraryBooks.Select(lb => lb.Book.AudibleProductId).ToList(); + var visibleIds = visibleLibraryBooks.Select(lb => lb.Book.AudibleProductId).ToList(); await LibraryCommands.RemoveBooksAsync(visibleIds); } #endregion