Added checkbox-based selection system and bulk actions in CardWindow #229

Open
Timo713 wants to merge 8 commits from Timo713/add-checkbox-selection-feature into master
Timo713 commented 2025-10-19 02:24:38 +00:00 (Migrated from github.com)

Summary

This change introduces an optional checkbox-based selection system to make managing multiple cards more intuitive and flexible.

Changes

  • Added a “Use checkboxes” option under the View menu, allowing users to mark cards without losing the active preview.
  • Marked cards behave identically to normal selections, supporting bulk actions, like delete, move and drag & drop.
  • Added Spacebar, Numpad 0, and double-click shortcuts to toggle a card’s marked state quickly.
  • Marked cards are preserved between refreshes, unless they are deleted or moved.
  • Added “Unmark all” under the Tools menu to clear all marked cards in one click.
  • A “Move to folder…” option that opens with the current folder preselected.
  • “Open in Explorer” now supports selected or marked cards if there are any and opens their location and selects them.

Why

Previously, selecting multiple cards using CTRL or SHIFT prevented the preview from updating, while clicking normally cleared all selections.
This made it cumbersome to review and manage multiple cards at once.

The new checkbox mode allows users to:

  • Freely mark cards while keeping the preview active.
  • Perform normal bulk actions (delete, move, open folder) on marked cards.

This makes managing large libraries smoother and more consistent with user expectations.

### Summary This change introduces an optional **checkbox-based selection system** to make managing multiple cards more intuitive and flexible. ### Changes * Added a **“Use checkboxes”** option under the **View** menu, allowing users to mark cards without losing the active preview. * Marked cards behave identically to normal selections, supporting bulk actions, like delete, move and drag & drop. * Added **Spacebar**, **Numpad 0**, and **double-click** shortcuts to toggle a card’s marked state quickly. * Marked cards are **preserved between refreshes**, unless they are deleted or moved. * Added **“Unmark all”** under the **Tools** menu to clear all marked cards in one click. * A **“Move to folder…”** option that opens with the current folder preselected. * **“Open in Explorer”** now supports selected or marked cards if there are any and opens their location and selects them. ### Why Previously, selecting multiple cards using **CTRL** or **SHIFT** prevented the preview from updating, while clicking normally cleared all selections. This made it cumbersome to review and manage multiple cards at once. The new checkbox mode allows users to: * Freely mark cards while keeping the preview active. * Perform normal bulk actions (delete, move, open folder) on marked cards. This makes managing large libraries smoother and more consistent with user expectations.
ManlyMarco (Migrated from github.com) requested changes 2025-10-19 20:24:04 +00:00
ManlyMarco (Migrated from github.com) left a comment

Thanks for the PR. It will need some changes to be merged unfortunately.

First, it would be easier to handle if the features were separated into different PRs. A bit late for that now but something to keep in mind in the future.

The checkboxes are a good option to add but I think they should be treated identically to a normal selection when the checkbox mode is enabled. Having checkboxes act differently from normal selection is going to be confusing to users.

The new open in explorer button seems superfluous, I think the existing open in explorer button should be updated to open with cards selected if there are any selected in the list.

The removed comments I mentioned should be restored since they contained useful information. Please avoid changing things unrelated to the main goal of the PR in the future.

If you want to discuss this PR outside of github you can find me on Koikatsu Discord server.

Thanks for the PR. It will need some changes to be merged unfortunately. First, it would be easier to handle if the features were separated into different PRs. A bit late for that now but something to keep in mind in the future. The checkboxes are a good option to add but I think they should be treated identically to a normal selection when the checkbox mode is enabled. Having checkboxes act differently from normal selection is going to be confusing to users. The new open in explorer button seems superfluous, I think the existing open in explorer button should be updated to open with cards selected if there are any selected in the list. The removed comments I mentioned should be restored since they contained useful information. Please avoid changing things unrelated to the main goal of the PR in the future. If you want to discuss this PR outside of github you can find me on Koikatsu Discord server.
@ -295,1 +311,3 @@
//RefreshThumbnails(true);
var toAdd = ShowInvalid ? list : list.Where(x => x is not UnknownCard).ToList();
listView.AddObjects(toAdd);
ManlyMarco (Migrated from github.com) commented 2025-10-19 20:04:29 +00:00

Please do not remove documentation comments.

Please do not remove documentation comments.
@ -337,4 +382,3 @@
if (token.IsCancellationRequested) return;
var large = listView.View == View.LargeIcon;
ManlyMarco (Migrated from github.com) commented 2025-10-19 20:04:01 +00:00

Please do not remove informational comments.

Please do not remove informational comments.
ManlyMarco (Migrated from github.com) commented 2025-10-19 20:06:29 +00:00

A better name would be something like GetSelectedCards.

A better name would be something like GetSelectedCards.
ManlyMarco (Migrated from github.com) commented 2025-10-19 20:08:09 +00:00

Why require the list to be in checkbox selection mode? It shouldn't matter what mode the list is in for features that work on selections.

Why require the list to be in checkbox selection mode? It shouldn't matter what mode the list is in for features that work on selections.
ManlyMarco (Migrated from github.com) commented 2025-10-19 20:12:25 +00:00

These could be combined into a single event handler, simply set all of the toggles to use the same method.

These could be combined into a single event handler, simply set all of the toggles to use the same method.
ManlyMarco (Migrated from github.com) commented 2025-10-19 20:15:16 +00:00

If the filtering logic was moved into the ModelFilter then rebuilding would become unnecessary, checking the toggles would just need to do a quick list refresh. Performance-wise it should be faster for when cards are still being actively loaded.

If the filtering logic was moved into the ModelFilter then rebuilding would become unnecessary, checking the toggles would just need to do a quick list refresh. Performance-wise it should be faster for when cards are still being actively loaded.
copilot-pull-request-reviewer[bot] (Migrated from github.com) reviewed 2025-10-19 20:30:58 +00:00
copilot-pull-request-reviewer[bot] (Migrated from github.com) left a comment

Pull Request Overview

Adds optional checkbox-based selection, bulk actions, folder utilities, and duplicate detection/filtering to CardWindow to improve multi-card management.

  • Checkbox selection with keyboard/mouse shortcuts and “Select marked” action
  • Bulk move to folder and “Open selected in Explorer” for selected cards
  • Duplicate filtering by multiple criteria with menu-driven toggles
Files not reviewed (1)
  • src/KKManager/Windows/Content/CardWindow.Designer.cs: Language not supported

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

## Pull Request Overview Adds optional checkbox-based selection, bulk actions, folder utilities, and duplicate detection/filtering to CardWindow to improve multi-card management. - Checkbox selection with keyboard/mouse shortcuts and “Select marked” action - Bulk move to folder and “Open selected in Explorer” for selected cards - Duplicate filtering by multiple criteria with menu-driven toggles <details> <summary>Files not reviewed (1)</summary> * **src/KKManager/Windows/Content/CardWindow.Designer.cs**: Language not supported </details> --- <sub>**Tip:** Customize your code reviews with copilot-instructions.md. <a href="/IllusionMods/KKManager/new/master/.github?filename=copilot-instructions.md" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Create the file</a> or <a href="https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">learn how to get started</a>.</sub>
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2025-10-19 20:30:57 +00:00

The null-coalescing and addition operators rely on precedence that makes this expression incorrect. Wrap each term to ensure each length null-coalesces before summation: (x.MissingPlugins?.Length ?? 0) + (x.MissingPluginsMaybe?.Length ?? 0) + (x.MissingZipmods?.Length ?? 0).

            var cardsWithMissingMods = selectedObjects.Where(x => ((x.MissingPlugins?.Length ?? 0) + (x.MissingPluginsMaybe?.Length ?? 0) + (x.MissingZipmods?.Length ?? 0)) > 0).ToList();
The null-coalescing and addition operators rely on precedence that makes this expression incorrect. Wrap each term to ensure each length null-coalesces before summation: (x.MissingPlugins?.Length ?? 0) + (x.MissingPluginsMaybe?.Length ?? 0) + (x.MissingZipmods?.Length ?? 0). ```suggestion var cardsWithMissingMods = selectedObjects.Where(x => ((x.MissingPlugins?.Length ?? 0) + (x.MissingPluginsMaybe?.Length ?? 0) + (x.MissingZipmods?.Length ?? 0)) > 0).ToList(); ```
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2025-10-19 20:30:58 +00:00

Corrected spelling of 'ExtenedDataCount' to 'ExtendedDataCount' in the CSV header.

                    writer.WriteLine("\"FileName\",\"Size\",\"CardType\",\"CharacterName\",\"Sex\",\"Personality\",\"CreatorID\",\"DataID\",\"Version\",\"ExtendedDataCount\",\"ExtendedSize\",\"MissingZipmods\",\"MissingPlugins\",\"MissingPluginsMaybe\"");
Corrected spelling of 'ExtenedDataCount' to 'ExtendedDataCount' in the CSV header. ```suggestion writer.WriteLine("\"FileName\",\"Size\",\"CardType\",\"CharacterName\",\"Sex\",\"Personality\",\"CreatorID\",\"DataID\",\"Version\",\"ExtendedDataCount\",\"ExtendedSize\",\"MissingZipmods\",\"MissingPlugins\",\"MissingPluginsMaybe\""); ```
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2025-10-19 20:30:57 +00:00

Avoid empty catch blocks; they swallow errors and make troubleshooting difficult. At minimum, log the exception (e.g., Debug.WriteLine or Console.WriteLine) or show a non-blocking notification; similar empty catches appear at 915, 931, 945, and 969.

            catch (Exception ex) { Console.WriteLine(ex); }
Avoid empty catch blocks; they swallow errors and make troubleshooting difficult. At minimum, log the exception (e.g., Debug.WriteLine or Console.WriteLine) or show a non-blocking notification; similar empty catches appear at 915, 931, 945, and 969. ```suggestion catch (Exception ex) { Console.WriteLine(ex); } ```
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2025-10-19 20:30:58 +00:00

To prevent the system "beep" and ensure the key press is fully suppressed in WinForms, also set e.SuppressKeyPress = true when handling the Space key.

                    e.Handled = true;
                    e.SuppressKeyPress = true;
To prevent the system "beep" and ensure the key press is fully suppressed in WinForms, also set e.SuppressKeyPress = true when handling the Space key. ```suggestion e.Handled = true; e.SuppressKeyPress = true; ```
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2025-10-19 20:30:57 +00:00

File.Move will throw on cross-volume moves (different drives). Fallback to a copy+delete on IOException (or detect different root paths) to reliably support moving to any folder; consider using File.Replace when overwriting on the same volume if desired.

                        try
                        {
                            File.Move(card.Location.FullName, candidate);
                            moved++;
                        }
                        catch (IOException)
                        {
                            // Fallback for cross-volume move: copy then delete
                            File.Copy(card.Location.FullName, candidate);
                            File.Delete(card.Location.FullName);
                            moved++;
                        }
                    }
                    catch
                    {
                        failed++;
                    }
File.Move will throw on cross-volume moves (different drives). Fallback to a copy+delete on IOException (or detect different root paths) to reliably support moving to any folder; consider using File.Replace when overwriting on the same volume if desired. ```suggestion try { File.Move(card.Location.FullName, candidate); moved++; } catch (IOException) { // Fallback for cross-volume move: copy then delete File.Copy(card.Location.FullName, candidate); File.Delete(card.Location.FullName); moved++; } } catch { failed++; } ```
Timo713 commented 2025-10-19 21:22:58 +00:00 (Migrated from github.com)

Thanks, Marco! I originally made this as a small QoL tweak for myself, but I don’t mind sharing it if it helps others too, and honestly, if it gets implemented, I won’t have to rebuild it for myself every time there’s an update, lol.

Since I’m not exactly a “real” programmer, I’ve been relying on AI to do the coding. So it’s mostly “vibe-coded,” and despite prompting it not to delete existing code or documentation, it sometimes changes or tries “optimizing” things anyway.

Sorry if that makes it a bit messy, I'm trying to get better at this. If you’ve got any tips on how to better handle this, especially when it comes to using AI to code and not messing with previous code, I’d really appreciate it. Thanks!

Thanks, Marco! I originally made this as a small QoL tweak for myself, but I don’t mind sharing it if it helps others too, and honestly, if it gets implemented, I won’t have to rebuild it for myself every time there’s an update, lol. Since I’m not exactly a “real” programmer, I’ve been relying on AI to do the coding. So it’s mostly “vibe-coded,” and despite prompting it not to delete existing code or documentation, it sometimes changes or tries “optimizing” things anyway. Sorry if that makes it a bit messy, I'm trying to get better at this. If you’ve got any tips on how to better handle this, especially when it comes to using AI to code and not messing with previous code, I’d really appreciate it. Thanks!
Timo713 (Migrated from github.com) reviewed 2025-10-19 21:23:24 +00:00
Timo713 (Migrated from github.com) commented 2025-10-19 21:23:24 +00:00

I did it because of the drag & drop feature, which only works with selected cards, but like you said, maybe checkboxes should be treated like normal selections when that mode is enabled.

I did it because of the drag & drop feature, which only works with selected cards, but like you said, maybe checkboxes should be treated like normal selections when that mode is enabled.
ManlyMarco commented 2025-10-20 02:25:42 +00:00 (Migrated from github.com)

Being a "real" programmer isn't all that difficult really, it just means you're able to problem solve and look up useful information. You can even ask the LLM for explanations and pointers to further learning (of course don't trust it blindly but this is a decent use case).

If you use Visual Studio then you should be able to use the "git changes" tab to selectively pick the changes you want and undo unnecessary changes. Most modern IDEs should have git integration like this, I suggest playing around with it a bit.

My suggestion would be to try to split this PR into two - just the checkbox feature and just the additional filter. It should be a pretty good opportunity to learn some git basics.

As I've mentioned before if you use discord you can reach out on there to ask for pointers.

Being a "real" programmer isn't all that difficult really, it just means you're able to problem solve and look up useful information. You can even ask the LLM for explanations and pointers to further learning (of course don't trust it blindly but this is a decent use case). If you use Visual Studio then you should be able to use the "git changes" tab to selectively pick the changes you want and undo unnecessary changes. Most modern IDEs should have git integration like this, I suggest playing around with it a bit. My suggestion would be to try to split this PR into two - just the checkbox feature and just the additional filter. It should be a pretty good opportunity to learn some git basics. As I've mentioned before if you use discord you can reach out on there to ask for pointers.
Timo713 commented 2025-10-20 08:34:55 +00:00 (Migrated from github.com)

Thanks a lot for the help! I'll definitely look into it. I think I managed to make the changes you requested, I still need to look into how to split this into two separate PRs. Just bear with me, I might be a little busy for the moment.

Should I make a new PR with only the checkboxes feature? I'll also include the fix you merged for the filename column in CardWindow. And until the checkbox one gets merged, I'll make another for the duplicate filter as well.

Thanks a lot for the help! I'll definitely look into it. I think I managed to make the changes you requested, I still need to look into how to split this into two separate PRs. Just bear with me, I might be a little busy for the moment. Should I make a new PR with only the checkboxes feature? I'll also include the fix you merged for the filename column in CardWindow. And until the checkbox one gets merged, I'll make another for the duplicate filter as well.
Timo713 commented 2025-10-25 00:08:56 +00:00 (Migrated from github.com)

I rolled back the changes to include only the checkbox feature and some of the requested adjustments, as well as other optimizations I updated in the 1st PR comment.
If this gets merged, I’ll make a separate PR for the duplicate filter feature.
Hope it’s now working as intended, sorry for the messy changes history!
If you prefer I open a new PR for this instead, I can do that too.

I rolled back the changes to include only the checkbox feature and some of the requested adjustments, as well as other optimizations I updated in the 1st PR comment. If this gets merged, I’ll make a separate PR for the duplicate filter feature. Hope it’s now working as intended, sorry for the messy changes history! If you prefer I open a new PR for this instead, I can do that too.
ManlyMarco commented 2025-10-25 15:07:31 +00:00 (Migrated from github.com)

Please mark the PR as ready for review once it is ready for final review.

Please mark the PR as ready for review once it is ready for final review.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin Timo713/add-checkbox-selection-feature:Timo713/add-checkbox-selection-feature
git switch Timo713/add-checkbox-selection-feature

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch master
git merge --no-ff Timo713/add-checkbox-selection-feature
git switch Timo713/add-checkbox-selection-feature
git rebase master
git switch master
git merge --ff-only Timo713/add-checkbox-selection-feature
git switch Timo713/add-checkbox-selection-feature
git rebase master
git switch master
git merge --no-ff Timo713/add-checkbox-selection-feature
git switch master
git merge --squash Timo713/add-checkbox-selection-feature
git switch master
git merge --ff-only Timo713/add-checkbox-selection-feature
git switch master
git merge Timo713/add-checkbox-selection-feature
git push origin master
Sign in to join this conversation.
No description provided.