From 0657d619dfb7190c0449697e1e5512a57f0ad95a Mon Sep 17 00:00:00 2001 From: Nate Bross Date: Tue, 19 May 2026 21:37:09 -0500 Subject: [PATCH] fix: make paste deduplication name-aware Paste collisions used to be content-only: pasting a clip whose XML matched any existing clip was silently skipped, regardless of name. This broke variant tracking (paste, rename, repaste leaves the user with only the renamed copy). Dedup now keys on (name, folder). Same name + same content skips as a true duplicate. Different name + same content lands as a variant. Same name + different content prompts the user via a new IClipCollisionPrompt with Replace / Keep both / Cancel choices and an apply-to-all option for batch (group) pastes. --- src/SharpFM/App.axaml.cs | 4 +- src/SharpFM/Dialogs/ClipCollisionDialog.axaml | 57 +++++++ .../Dialogs/ClipCollisionDialog.axaml.cs | 60 +++++++ src/SharpFM/Dialogs/IClipCollisionPrompt.cs | 30 ++++ .../Dialogs/NullClipCollisionPrompt.cs | 17 ++ .../Dialogs/WindowClipCollisionPrompt.cs | 17 ++ src/SharpFM/ViewModels/MainWindowViewModel.cs | 90 +++++++--- .../ViewModels/MainWindowViewModelTests.cs | 159 +++++++++++++++++- 8 files changed, 407 insertions(+), 27 deletions(-) create mode 100644 src/SharpFM/Dialogs/ClipCollisionDialog.axaml create mode 100644 src/SharpFM/Dialogs/ClipCollisionDialog.axaml.cs create mode 100644 src/SharpFM/Dialogs/IClipCollisionPrompt.cs create mode 100644 src/SharpFM/Dialogs/NullClipCollisionPrompt.cs create mode 100644 src/SharpFM/Dialogs/WindowClipCollisionPrompt.cs diff --git a/src/SharpFM/App.axaml.cs b/src/SharpFM/App.axaml.cs index 211c402..2c7efb2 100644 --- a/src/SharpFM/App.axaml.cs +++ b/src/SharpFM/App.axaml.cs @@ -43,11 +43,13 @@ public override void OnFrameworkInitializationCompleted() Services = services.BuildServiceProvider(); var inputPrompt = new WindowInputPrompt(desktop.MainWindow); + var collisionPrompt = new WindowClipCollisionPrompt(desktop.MainWindow); var viewModel = new MainWindowViewModel( logger, Services.GetRequiredService(), Services.GetRequiredService(), - inputPrompt); + inputPrompt, + collisionPrompt); // Load plugins var pluginHost = new PluginHost(viewModel, loggerFactory, inputPrompt); diff --git a/src/SharpFM/Dialogs/ClipCollisionDialog.axaml b/src/SharpFM/Dialogs/ClipCollisionDialog.axaml new file mode 100644 index 0000000..34e0aed --- /dev/null +++ b/src/SharpFM/Dialogs/ClipCollisionDialog.axaml @@ -0,0 +1,57 @@ + + + + + + + + + + + +