From a3c54bbb035e1d477cf86abde22e82ecc4cdc272 Mon Sep 17 00:00:00 2001 From: netquick Date: Mon, 24 Aug 2026 15:04:04 +0200 Subject: [PATCH] Add Git overlay, operation tools, and virtualized preview so large folders stay responsive. Co-authored-by: Cursor --- Backlog.md | 823 ++++++++++++++++++ docs/Documentation.md | 343 ++++++++ src/Explorer.Analysis/AnalysisService.cs | 42 + src/Explorer.App/AboutWindow.xaml | 32 + src/Explorer.App/AboutWindow.xaml.cs | 24 + src/Explorer.App/App.xaml | 77 +- src/Explorer.App/AppServices.cs | 34 +- src/Explorer.App/BatchRenameWindow.xaml | 86 ++ src/Explorer.App/BatchRenameWindow.xaml.cs | 26 + src/Explorer.App/Converters.cs | 48 - src/Explorer.App/DocumentationLoader.cs | 55 ++ src/Explorer.App/DocumentationWindow.xaml | 38 + src/Explorer.App/DocumentationWindow.xaml.cs | 108 +++ src/Explorer.App/Explorer.App.csproj | 2 + src/Explorer.App/FolderSyncWindow.xaml | 77 ++ src/Explorer.App/FolderSyncWindow.xaml.cs | 39 + src/Explorer.App/FolderViewport.cs | 155 ++++ src/Explorer.App/MainWindow.xaml | 184 +++- src/Explorer.App/MainWindow.xaml.cs | 203 ++++- src/Explorer.App/MarkdownFlowConverter.cs | 290 ++++++ src/Explorer.App/OperationProfilesWindow.xaml | 108 +++ .../OperationProfilesWindow.xaml.cs | 84 ++ src/Explorer.App/ReorganizeWindow.xaml | 86 ++ src/Explorer.App/ReorganizeWindow.xaml.cs | 37 + src/Explorer.App/SettingsWindow.xaml | 20 +- src/Explorer.App/SettingsWindow.xaml.cs | 34 +- src/Explorer.App/ShellIconConverter.cs | 9 + src/Explorer.App/ThumbnailService.cs | 335 +++++++ src/Explorer.App/VirtualizingWrapPanel.cs | 237 +++++ src/Explorer.Application/BrowseHydration.cs | 65 ++ src/Explorer.Application/BrowseService.cs | 783 +++++++++++++---- src/Explorer.Application/CursorLocator.cs | 30 + .../Explorer.Application.csproj | 3 + .../FileOperationProfilePlanner.cs | 251 ++++++ src/Explorer.Application/FolderListingSort.cs | 71 ++ src/Explorer.Application/FolderSyncPlanner.cs | 275 ++++++ src/Explorer.Application/GitLocator.cs | 39 + .../GitPorcelainParser.cs | 98 +++ src/Explorer.Application/GitRepoDetector.cs | 53 ++ src/Explorer.Application/IArchiveExecutor.cs | 35 + .../IGitStatusProvider.cs | 17 + .../IRecycleBinCatalog.cs | 10 +- .../LocationVisibility.cs | 5 + src/Explorer.Application/LruCache.cs | 63 ++ src/Explorer.Application/MarkdownParser.cs | 258 ++++++ src/Explorer.Application/RenamePlanner.cs | 288 ++++++ src/Explorer.Application/ReorganizePlanner.cs | 192 ++++ src/Explorer.Application/SevenZipLocator.cs | 37 + src/Explorer.Application/SourceManager.cs | 27 + .../StorageProviderRegistry.cs | 37 +- .../ThumbnailScheduler.cs | 233 +++++ .../UiPreferencesStore.cs | 120 ++- .../Abstractions/IIndexStore.cs | 36 + src/Explorer.Domain/Abstractions/Platform.cs | 13 + src/Explorer.Domain/AppConstants.cs | 3 +- src/Explorer.Domain/ArchiveFormats.cs | 14 + src/Explorer.Domain/BrowseProgress.cs | 41 + src/Explorer.Domain/DuplicateClassifier.cs | 136 +++ src/Explorer.Domain/Entities.cs | 56 +- src/Explorer.Domain/Enums.cs | 76 +- src/Explorer.Domain/FileClassifier.cs | 170 ++++ src/Explorer.Domain/GitStatus.cs | 47 + src/Explorer.Domain/LocationRoots.cs | 3 +- src/Explorer.Domain/OperationPlan.cs | 35 + src/Explorer.Domain/OperationProfile.cs | 44 + src/Explorer.Domain/OrganizeDestinations.cs | 53 ++ src/Explorer.Domain/RenameRules.cs | 39 + src/Explorer.Domain/SyncProfile.cs | 19 + src/Explorer.Domain/WindowsFileNames.cs | 127 +++ .../FileOperationErrors.cs | 22 + .../FileOperationService.cs | 39 + .../FolderSyncService.cs | 191 ++++ .../IOperationExecutor.cs | 9 + .../NativeFileOperationExecutor.cs | 441 ++++++++++ .../OperationAvailability.cs | 88 ++ .../OperationProfileService.cs | 262 ++++++ .../RenameBatchService.cs | 79 ++ .../ReorganizeService.cs | 108 +++ src/Explorer.FileOperations/TransferQueue.cs | 432 +++++---- .../IThumbnailService.cs | 10 + .../RangeObservableCollection.cs | 43 + .../ViewModels/BatchRenameViewModel.cs | 123 +++ .../ViewModels/DuplicateViewModel.cs | 197 ++++- .../ViewModels/ExplorerPaneViewModel.cs | 317 +++++-- .../ViewModels/ExplorerTabViewModel.cs | 6 +- .../ViewModels/FolderItemViewModel.cs | 39 +- .../ViewModels/FolderSyncViewModel.cs | 228 +++++ .../ViewModels/MainViewModel.cs | 300 ++++++- .../ViewModels/NavigationTreeViewModel.cs | 35 +- .../ViewModels/OperationProfilesViewModel.cs | 320 +++++++ .../ViewModels/ReorganizeViewModel.cs | 118 +++ .../ViewModels/TransferQueueViewModel.cs | 70 +- .../AnalysisHistoryHashStores.cs | 3 +- .../FileRelationStore.cs | 94 ++ src/Explorer.Storage.Sqlite/MiscStores.cs | 134 ++- .../OperationProfileStore.cs | 131 +++ .../RenameBatchStore.cs | 67 ++ src/Explorer.Storage.Sqlite/SchemaScript.cs | 87 +- .../SqliteIndexStore.cs | 163 +++- .../SyncProfileStore.cs | 99 +++ src/Explorer.Windows/NativeMethods.cs | 18 + .../SevenZipArchiveExecutor.cs | 155 ++++ .../WindowsFileSystemEnumerator.cs | 107 ++- .../WindowsGitStatusProvider.cs | 105 +++ .../WindowsRecycleBinCatalog.cs | 55 ++ .../WindowsShellFileOperations.cs | 15 + .../WindowsWorkspaceLauncher.cs | 62 ++ .../Explorer.Analysis.Tests/AnalysisTests.cs | 86 ++ .../BrowseHydrationTests.cs | 373 ++++++++ .../BrowseServiceTests.cs | 194 ++++- .../CloudProviderTests.cs | 20 + .../FileOperationProfilePlannerTests.cs | 194 +++++ .../FolderSyncPlannerTests.cs | 240 +++++ .../GitPorcelainParserTests.cs | 98 +++ .../MarkdownParserTests.cs | 69 ++ .../RenamePlannerTests.cs | 187 ++++ .../ReorganizePlannerTests.cs | 166 ++++ .../SevenZipLocatorTests.cs | 30 + .../SourceManagerTests.cs | 86 +- .../ThumbnailSchedulerTests.cs | 170 ++++ .../UiPreferencesStoreTests.cs | 48 +- tests/Explorer.Domain.Tests/DomainTests.cs | 171 ++++ .../FileOperationTests.cs | 1 + .../FolderSyncServiceTests.cs | 164 ++++ .../OperationProfileServiceTests.cs | 165 ++++ .../TransferQueueTests.cs | 373 +++++++- tests/Explorer.Storage.Tests/StorageTests.cs | 236 +++++ 127 files changed, 14748 insertions(+), 633 deletions(-) create mode 100644 Backlog.md create mode 100644 docs/Documentation.md create mode 100644 src/Explorer.App/AboutWindow.xaml create mode 100644 src/Explorer.App/AboutWindow.xaml.cs create mode 100644 src/Explorer.App/BatchRenameWindow.xaml create mode 100644 src/Explorer.App/BatchRenameWindow.xaml.cs create mode 100644 src/Explorer.App/DocumentationLoader.cs create mode 100644 src/Explorer.App/DocumentationWindow.xaml create mode 100644 src/Explorer.App/DocumentationWindow.xaml.cs create mode 100644 src/Explorer.App/FolderSyncWindow.xaml create mode 100644 src/Explorer.App/FolderSyncWindow.xaml.cs create mode 100644 src/Explorer.App/FolderViewport.cs create mode 100644 src/Explorer.App/MarkdownFlowConverter.cs create mode 100644 src/Explorer.App/OperationProfilesWindow.xaml create mode 100644 src/Explorer.App/OperationProfilesWindow.xaml.cs create mode 100644 src/Explorer.App/ReorganizeWindow.xaml create mode 100644 src/Explorer.App/ReorganizeWindow.xaml.cs create mode 100644 src/Explorer.App/ThumbnailService.cs create mode 100644 src/Explorer.App/VirtualizingWrapPanel.cs create mode 100644 src/Explorer.Application/BrowseHydration.cs create mode 100644 src/Explorer.Application/CursorLocator.cs create mode 100644 src/Explorer.Application/FileOperationProfilePlanner.cs create mode 100644 src/Explorer.Application/FolderListingSort.cs create mode 100644 src/Explorer.Application/FolderSyncPlanner.cs create mode 100644 src/Explorer.Application/GitLocator.cs create mode 100644 src/Explorer.Application/GitPorcelainParser.cs create mode 100644 src/Explorer.Application/GitRepoDetector.cs create mode 100644 src/Explorer.Application/IArchiveExecutor.cs create mode 100644 src/Explorer.Application/IGitStatusProvider.cs create mode 100644 src/Explorer.Application/LruCache.cs create mode 100644 src/Explorer.Application/MarkdownParser.cs create mode 100644 src/Explorer.Application/RenamePlanner.cs create mode 100644 src/Explorer.Application/ReorganizePlanner.cs create mode 100644 src/Explorer.Application/SevenZipLocator.cs create mode 100644 src/Explorer.Application/ThumbnailScheduler.cs create mode 100644 src/Explorer.Domain/BrowseProgress.cs create mode 100644 src/Explorer.Domain/DuplicateClassifier.cs create mode 100644 src/Explorer.Domain/FileClassifier.cs create mode 100644 src/Explorer.Domain/GitStatus.cs create mode 100644 src/Explorer.Domain/OperationPlan.cs create mode 100644 src/Explorer.Domain/OperationProfile.cs create mode 100644 src/Explorer.Domain/OrganizeDestinations.cs create mode 100644 src/Explorer.Domain/RenameRules.cs create mode 100644 src/Explorer.Domain/SyncProfile.cs create mode 100644 src/Explorer.Domain/WindowsFileNames.cs create mode 100644 src/Explorer.FileOperations/FileOperationErrors.cs create mode 100644 src/Explorer.FileOperations/FolderSyncService.cs create mode 100644 src/Explorer.FileOperations/IOperationExecutor.cs create mode 100644 src/Explorer.FileOperations/NativeFileOperationExecutor.cs create mode 100644 src/Explorer.FileOperations/OperationAvailability.cs create mode 100644 src/Explorer.FileOperations/OperationProfileService.cs create mode 100644 src/Explorer.FileOperations/RenameBatchService.cs create mode 100644 src/Explorer.FileOperations/ReorganizeService.cs create mode 100644 src/Explorer.Presentation/IThumbnailService.cs create mode 100644 src/Explorer.Presentation/RangeObservableCollection.cs create mode 100644 src/Explorer.Presentation/ViewModels/BatchRenameViewModel.cs create mode 100644 src/Explorer.Presentation/ViewModels/FolderSyncViewModel.cs create mode 100644 src/Explorer.Presentation/ViewModels/OperationProfilesViewModel.cs create mode 100644 src/Explorer.Presentation/ViewModels/ReorganizeViewModel.cs create mode 100644 src/Explorer.Storage.Sqlite/FileRelationStore.cs create mode 100644 src/Explorer.Storage.Sqlite/OperationProfileStore.cs create mode 100644 src/Explorer.Storage.Sqlite/RenameBatchStore.cs create mode 100644 src/Explorer.Storage.Sqlite/SyncProfileStore.cs create mode 100644 src/Explorer.Windows/SevenZipArchiveExecutor.cs create mode 100644 src/Explorer.Windows/WindowsGitStatusProvider.cs create mode 100644 src/Explorer.Windows/WindowsRecycleBinCatalog.cs create mode 100644 src/Explorer.Windows/WindowsWorkspaceLauncher.cs create mode 100644 tests/Explorer.Application.Tests/BrowseHydrationTests.cs create mode 100644 tests/Explorer.Application.Tests/FileOperationProfilePlannerTests.cs create mode 100644 tests/Explorer.Application.Tests/FolderSyncPlannerTests.cs create mode 100644 tests/Explorer.Application.Tests/GitPorcelainParserTests.cs create mode 100644 tests/Explorer.Application.Tests/MarkdownParserTests.cs create mode 100644 tests/Explorer.Application.Tests/RenamePlannerTests.cs create mode 100644 tests/Explorer.Application.Tests/ReorganizePlannerTests.cs create mode 100644 tests/Explorer.Application.Tests/SevenZipLocatorTests.cs create mode 100644 tests/Explorer.Application.Tests/ThumbnailSchedulerTests.cs create mode 100644 tests/Explorer.FileOperations.Tests/FolderSyncServiceTests.cs create mode 100644 tests/Explorer.FileOperations.Tests/OperationProfileServiceTests.cs diff --git a/Backlog.md b/Backlog.md new file mode 100644 index 0000000..bc1cfac --- /dev/null +++ b/Backlog.md @@ -0,0 +1,823 @@ +# Explorer Workbench - Backlog + +> Personal file management workbench. +> +> Goal: Make working with files faster - not necessarily the filesystem itself. +> +> **Primary success metric:** One happy customer. 😎 + +--- + +## Core Principles + +### Windows remains the source of truth + +Explorer Workbench may discover, index, display and organize Windows resources, but should not silently modify Windows configuration. + +Example: + +- Removing `Z:` from Workbench removes the Workbench location and its index data. +- It does **not** disconnect the Windows network drive. +- Existing Windows resources should be discoverable/importable again. + +### Workbench owns the workflow + +Specialized tools may provide execution capabilities. + +Possible providers: + +- Robocopy - robust file transfers +- 7-Zip - archive operations +- FFmpeg - media conversion +- Git - repository operations + +Explorer Workbench provides: + +- UI +- orchestration +- metadata +- index +- profiles +- queue +- status +- history + +### File Operations Queue is the execution engine + +Whenever possible, features that modify files should create operations instead of modifying the filesystem directly. + +Examples: + +- Copy +- Move +- Recycle +- Delete +- Rename +- Extract +- Compress +- Convert +- Sync +- Reorganize + +### Analyze aggressively, modify conservatively + +Analysis may be ambitious. + +Filesystem modifications should be predictable, reviewable and safe. + +Complex operations should preferably follow: + +`Analyze -> Preview -> Operation Plan -> Queue -> Execute` + +### Configuration rule + +If both behaviors are useful depending on the situation: + +**Make it an option.** + +--- + +# Current Features + +## Navigation + +- [x] Group locations into `This PC`, `Network` and `Cloud` +- [x] Optional grouping via Settings +- [x] Remove locations from Workbench +- [x] Remove associated index/database data +- [x] Do not modify Windows mappings when removing Workbench locations +- [x] Add network/cloud locations +- [x] Discover/import existing Windows network drives +- [x] Restore a previously removed Workbench location from Windows discovery + +## UI + +- [x] Classic application menu +- [x] Icon-based toolbar +- [x] Settings dialog +- [x] Help menu with About and in-app Documentation +- [x] Expandable Settings architecture +- [x] Show `Free Space` next to `Size` where meaningful +- [x] Consistent capacity information for local/network/cloud providers +- [x] Organize folder (classify → preview → queue moves) + +## Search / Index + +- [x] Central filesystem index +- [x] Fast indexed search +- [ ] Search offline locations +- [x] Search archive contents +- [ ] Store originating machine/location +- [ ] Multi-PC search +- [ ] Richer metadata indexing + +## Storage Analysis + +- [x] Storage usage analysis +- [x] WinDirStat-style functionality +- [x] Duplicate detection +- [x] Duplicate classification +- [x] Distinguish intentional duplicates +- [x] Recognize Sync copies +- [ ] Recognize Backup copies +- [x] Detect hardlinks + +--- + +# File Operations Queue + +## Implemented + +- [x] Central File Operations Queue +- [x] Copy +- [x] Move +- [x] Move to Recycle Bin +- [x] Queue Rename +- [x] Queue Extract +- [x] Queue Compress +- [x] Sequential execution +- [x] Pause / Resume +- [x] Pause all +- [x] Progress display +- [x] Queue status +- [x] Reorder operations +- [x] Remove queued operations +- [x] Clear finished operations +- [x] Auto-clear when done +- [x] Compact queue status in main UI +- [x] Persist queue across Workbench restarts +- [x] Retry failed operations +- [x] `Waiting for destination` state +- [x] Resume automatically when destination becomes available +- [x] Handle temporarily unavailable network shares +- [x] Handle removable media (wait until reachable) +- [x] Detect file locks (Failed + Retry) +- [x] Operation history (append-only) + +## Planned + +- [ ] Conflict resolution +- [x] Undo last rename batch +- [ ] Undo copy / move +- [ ] Resource-aware scheduling + +### Resource-aware scheduling + +Potential future behavior: + +Instead of always running exactly one operation, allow concurrent operations when they do not compete for the same I/O resources. + +Example: + +`C: -> D:` and `NAS -> USB` may run simultaneously. + +Two operations using the same physical source/target should normally remain serialized. + +--- + +# Protected Windows Filesystem Locations + +## Visibility + +- [x] Hidden file support +- [x] Setting: `Show protected system locations` +- [x] Detect `FileAttributes.Hidden` +- [x] Detect `FileAttributes.System` +- [x] Classify known protected Windows locations +- [x] Distinguish `Access denied` from empty folders + +Known examples: + +- `System Volume Information` +- `$RECYCLE.BIN` +- `Recovery` +- `pagefile.sys` +- `hiberfil.sys` + +## Size calculation + +Never display: + +`0 B` + +when the actual state is: + +`Unknown because access was denied` + +Possible states: + +- Calculated +- Partial +- Unknown +- Access denied + +## Elevated scan + +- [ ] Detect when elevation would provide additional information +- [ ] Optional elevated/deep scan +- [ ] Never silently elevate +- [ ] Keep normal Workbench operation non-elevated + +## Recycle Bin + +- [x] Classify `$RECYCLE.BIN` specially +- [x] Do not expose it merely as a normal filesystem folder +- [x] Show logical Recycle Bin information +- [x] Number of deleted items +- [x] Used space +- [x] Open Recycle Bin +- [x] Empty Recycle Bin + +--- + +# Folder Sync + +Goal: Replace the relevant AllSync workflows. + +## Sync modes + +- [x] Copy / Update +- [x] Mirror +- [ ] Two-way sync +- [ ] Versioned backup + +Two-way sync should be implemented later because it requires proper conflict and deletion tracking. + +## Integration + +- [x] Analyze differences +- [x] Generate operation plan +- [x] Submit operations to File Operations Queue +- [x] Preview before execution +- [x] Conflict detection +- [ ] Sync history + +## Offline / removable locations + +- [x] Detect target availability +- [x] Wait when target is offline +- [x] Automatically continue when target returns +- [x] Identify removable media using stable volume identity +- [x] Do not depend only on drive letters +- [x] Trigger sync when known media is connected + +Example: + +`When PhotosBackup becomes available -> run Photos Sync` + +## Duplicate awareness + +Files intentionally created by Folder Sync should be marked as intentional duplicates. + +Possible classification: + +- `Accidental` +- `Synchronized` +- `Backup` +- `Unknown` + +The Duplicate Finder hides intentional duplicates by default. Sync and backup tags are written when those operations exist. + +--- + +# Batch Rename + +Goal: Replace FileRenamer workflows. + +## Rename rules + +- [x] Search / Replace +- [x] Regex +- [x] Prefix +- [x] Suffix +- [x] Counter +- [x] Counter padding +- [x] Case conversion +- [x] Extension handling +- [ ] Metadata placeholders + +Potential placeholders: + +- `{CreatedDate}` +- `{ModifiedDate}` +- `{Counter}` +- `{Width}` +- `{Height}` +- `{Artist}` +- `{Title}` +- `{Project}` +- `{Extension}` + +## Workflow + +`Select -> Configure -> Preview -> Validate -> Queue` + +- [x] Preview all resulting names +- [x] Detect collisions +- [x] Detect invalid filenames +- [x] Add Rename operations to File Operations Queue +- [x] Store `OldPath -> NewPath` +- [x] Support Undo for completed rename batches + +--- + +# File Operation Profiles + +Reusable workflows built from Workbench operations. + +## Core + +- [x] Create profile +- [x] Edit profile +- [x] Delete profile +- [x] Duplicate profile +- [x] Run profile +- [x] Preview operation plan +- [x] Add resulting operations to queue + +## Example: Archive Project + +1. Verify Git status +2. Require clean working tree +3. Exclude `.git`, `bin`, `obj`, `.vs` +4. Compress using 7-Zip +5. Generate SHA-256 +6. Copy archive to NAS +7. Verify destination +8. Recycle source only if all previous steps succeeded + +## Example: Phone Videos + +1. Find matching videos +2. Convert to configured format +3. Preserve timestamps +4. Copy converted files to Media +5. Archive originals +6. Queue cleanup + +## Example: Clean Downloads + +Classify files and propose: + +- Installers -> Software +- Images -> Pictures +- Video -> Media +- Archives -> Archive +- Git repositories -> Development +- Unknown -> Leave untouched + +Available as **Tools → Organize folder…** and **Organize this folder…** on a directory. Suggestions only; nothing moves until Queue. + +## Profile triggers + +- [x] Manual +- [x] Context menu: `Run Profile` +- [x] Drag files onto profile +- [x] When location becomes available +- [x] When removable media is connected +- [ ] Scheduled +- [ ] Folder watcher + +--- + +# Archives + +## Supported concepts + +- [x] ZIP +- [x] 7z +- [x] RAR +- [x] Additional archive formats through providers + +## Indexing + +- [x] Scan archive contents without extraction +- [x] Add archive entries to search index +- [x] Search inside archives +- [x] Display archive path as virtual hierarchy + +Example search result: + +`\\NAS\Archive\2019-backup.7z\Projects\Explorer\README.md` + +even when the NAS is currently offline. + +## Operations + +- [x] Extract +- [x] Compress +- [x] Add to archive +- [x] Verify archive +- [x] Queue archive operations + +Potential provider: + +`7-Zip` + +--- + +# File Classification + +Goal: Understand what files and folders represent rather than relying only on extensions. + +## Initial categories + +- [x] Media (Photos / Video / Audio) +- [x] Photos +- [x] Video +- [x] Audio +- [x] Documents +- [x] Code repositories +- [x] Installers +- [x] Backups (classified; left in place) +- [x] Archives +- [x] System data +- [x] Unknown + +## Detection signals + +- [x] File extension +- [ ] MIME/content signature +- [x] Folder structure +- [x] Git metadata +- [ ] Media metadata +- [x] Known application structures (`node_modules`, `bin`, `obj`, `.vs`) +- [x] File age (old installers flagged in preview) +- [ ] File relationships +- [ ] Index metadata + +--- + +# Reorganization / Consolidation + +Use file classification and metadata to propose better organization. + +## Concepts + +- [x] Analyze directory +- [x] Classify contents +- [x] Detect misplaced files +- [ ] Detect redundant files +- [x] Detect old installers +- [x] Detect old build output +- [ ] Detect archived projects +- [x] Generate reorganization proposal +- [x] Preview proposed operations +- [x] Submit approved operations to queue + +Important: + +**Never automatically reorganize based only on classification.** + +Always prefer: + +`Analyze -> Suggest -> Review -> Queue` + +--- + +# Multi-PC + +Goal: Search and manage the user's complete file environment rather than only the current PC. + +## Machines + +- [ ] Register Workbench machine +- [ ] Assign machine identity +- [ ] Store machine name with indexed files +- [ ] Track last-seen timestamp +- [ ] Track online/offline state + +## Search + +Example: + +Search: `wallet.dat` + +Results: + +- `Desktop-PC -> D:\Backup\wallet.dat` +- `Laptop -> C:\Archive\wallet.dat` +- `NAS -> backup-2019.7z\Crypto\wallet.dat` + +## Offline behavior + +- [ ] Keep index searchable while machine is offline +- [ ] Show last known location +- [ ] Show last indexed timestamp +- [ ] Queue operations requiring offline machine +- [ ] Resume when machine becomes available + +## Future + +- [ ] Transfer files between Workbench machines +- [ ] Remote filesystem browsing +- [ ] Remote indexing +- [ ] Shared operation queue / agent model + +--- + +# Secure Storage + +## Concepts + +- [ ] CryptDrive/Vault integration +- [ ] Secure Storage location category +- [ ] Detect mounted/unmounted state +- [ ] Index policy for encrypted locations +- [ ] Optional metadata-only index +- [ ] Security-sensitive search behavior + +Workbench should preferably integrate existing encryption technology rather than implement cryptography itself. + +--- + +# Conversion + +Conversions should be represented as File Operations. + +## Media + +Potential provider: + +`FFmpeg` + +Possible operations: + +- [ ] Video conversion +- [ ] Audio conversion +- [ ] Codec conversion +- [ ] Resolution conversion +- [ ] Extract audio +- [ ] Generate thumbnails + +## Images + +- [ ] HEIC -> JPEG +- [ ] PNG -> JPEG +- [ ] Resize +- [ ] Rotate +- [ ] Metadata preservation/removal + +## Workflow + +Conversions should support: + +`Input -> Conversion Profile -> Preview -> Queue` + +and be usable inside File Operation Profiles. + +--- + +# Git Integration + +Workbench should recognize repositories but not reimplement Git. + +Potential provider: + +`git` + +## Repository detection + +- [x] Detect Git repositories +- [x] Show current branch +- [x] Show modified count +- [x] Show untracked count +- [x] Show ahead/behind state + +Example: + +`Explorer-Workbench main 3 modified 1 untracked` + +## Actions + +- [ ] Status +- [ ] View Changes +- [ ] Commit +- [ ] Pull +- [ ] Push +- [ ] Fetch +- [x] Open terminal here +- [x] Open in Cursor + +## Profiles + +Git state may be used as a profile condition. + +Example: + +`Archive Project` + +requires: + +`Working tree clean` + +before archive operations continue. + +--- + +# Sharing + +## Basic sharing + +- [ ] Share file +- [ ] Share folder +- [ ] Copy share link +- [ ] Temporary shares +- [ ] Expiration +- [ ] Password protection +- [ ] Read-only permissions + +## Providers + +Potential integrations: + +- [ ] Nextcloud +- [ ] Network shares +- [ ] Other cloud providers + +## Package for Sharing + +Example profile: + +1. Exclude unnecessary files +2. Clean temporary data +3. Compress +4. Encrypt +5. Upload +6. Create expiring share link +7. Copy link to clipboard +8. Queue temporary archive cleanup + +--- + +# External Tool / Provider Integration + +## Robocopy + +Status: + +**Documentation review / knowledge transfer pending. 😏** + +Potential uses: + +- [ ] Restartable copies +- [ ] Network transfers +- [ ] Retry handling +- [ ] Backup-mode access +- [ ] Mirror operations +- [ ] Metadata/ACL preservation + +Possible architecture: + +`RobocopyTransferProvider` + +Workbench retains ownership of: + +- Queue +- Progress +- State +- UI +- Retry policy +- History + +Robocopy performs selected low-level transfers. + +## 7-Zip + +`SevenZipArchiveExecutor` (`IArchiveExecutor`) + +Discovery: Settings path, then Program Files, then PATH. Missing 7-Zip fails the queued job with an install hint. 7-Zip is not bundled. + +## FFmpeg + +Potential: + +`MediaConversionProvider` + +## Git + +`WindowsGitStatusProvider` (`IGitStatusProvider`) + +Discovery: Settings path, then Program Files, then PATH. Missing git.exe means no badge. Git is not bundled. Workbench does not commit, push, or pull. + +Potential later: + +`IGitCommandProvider` + +--- + +# Future Intelligence + +## File relationships + +Workbench should eventually understand relationships between files. + +Examples: + +- Duplicate +- Sync copy +- Backup copy +- Converted version +- Archived version +- Renamed version +- Source/output relationship + +This allows questions such as: + +> Which duplicates are accidental? + +instead of merely: + +> Which files have the same hash? + +## Forgotten Files + +Potential analysis: + +- Files not modified for many years +- Files not accessed for many years +- Old backups +- Forgotten projects +- Large unused files +- Old installers +- Historical archives + +Possible feature name: + +`Forgotten Files` + +--- + +# Architectural Direction + +Long-term conceptual model: + + Filesystems / Providers + | + v + Scanner + | + v + Metadata Index + | + v + Intelligence Layer + | + +-----+-----+ + | | + v v + Workbench Profiles + | | + +-----+-----+ + | + v + File Operations Queue + | + v + Execution Providers + +The Workbench should increasingly understand: + +- What is this? +- Where is it? +- Which machine has it? +- Is it currently available? +- Is there another copy? +- Why does another copy exist? +- Is it part of a sync or backup? +- How much space does it consume? +- What operations are safe? +- What does the user want to do with it? + +--- + +# Replaced / Potentially Replaced Tools + +| Tool | Workbench capability | +| --- | --- | +| Windows Explorer | Navigation / file management | +| WinDirStat | Storage analysis | +| WhereIsIt? | Indexed catalog / offline search | +| AllSync | Folder synchronization | +| FileRenamer | Batch rename | +| Archive tools | Archive workflows | +| Conversion tools | Profile-driven conversion | +| Various sharing workflows | Integrated sharing | + +The goal is not necessarily to completely replace every specialized tool. + +The goal is to make Explorer Workbench the **central working environment** from which those capabilities are orchestrated. + +--- + +# Definition of Done + +Explorer Workbench is never truly finished. + +A feature is useful when it improves the actual workflow of the primary user. + +A release is successful when: + +> Domi realizes he has not voluntarily opened Windows Explorer all week. + +😎 \ No newline at end of file diff --git a/docs/Documentation.md b/docs/Documentation.md new file mode 100644 index 0000000..3017bde --- /dev/null +++ b/docs/Documentation.md @@ -0,0 +1,343 @@ +# Explorer Workbench + +Personal file management workbench for Windows. The goal is to make **working with files** faster — not to replace the filesystem, and not to silently change Windows configuration. + +Mental model: + +> Open Explorer Workbench → see files → manage files → search immediately → analyze storage. + +Windows remains the source of truth. Removing a location from Workbench removes Workbench’s index data for it. It does **not** disconnect a network drive, unlink OneDrive, or change Explorer settings. + +Version documented here: **0.1** (schema 8). This file is the user guide. Edit it in any text editor; Explorer Workbench reloads it when you open **Help → Documentation**. + +--- + +## What it is (and is not) + +Workbench **does**: + +- Browse live folders (local, removable, network, cloud mounts) +- Index locations you choose, then search and analyze them +- Queue copy, move, recycle, rename, archive, sync, and organize work +- Overlay Git and cloud status without becoming a Git client or a sync engine + +Workbench **does not**: + +- Two-way sync +- Commit, push, or pull +- Convert media (no FFmpeg in this build) +- Hydrate online-only cloud files just to look at them +- Change Windows drive mappings or cloud client folders + +Specialized tools still do specialized jobs. 7-Zip compresses. Git reports status. Workbench orchestrates. + +--- + +## First launch + +1. This PC lists local and removable volumes Windows already knows. +2. Browsing works with an empty index. +3. Folder sizes, search, duplicates, and storage analysis need an index. Use the banner **Build index**, **Tools → Locations → Index this location**, or the toolbar **Index** control. +4. Data lives under `%LocalAppData%\ExplorerWorkbench\` — never beside the executable. + +| Path | Contents | +| --- | --- | +| `%LocalAppData%\ExplorerWorkbench\index.db` | Index, queue, profiles | +| `%LocalAppData%\ExplorerWorkbench\logs\` | Rolling logs | +| `%LocalAppData%\ExplorerWorkbench\ui-preferences.txt` | Theme, layout, tool paths, organize destinations | + +--- + +## Window layout + +- **Title bar** — Explorer Workbench; minimize / maximize / close. +- **Menu** — File, View, Tools, Settings, Help. Tools is grouped: Storage, Locations, File Operations (including Archives), Automation, Development, Recycle Bin. +- **Toolbar** — path, navigation, view mode, search, storage, queue summary. +- **Tree** — This PC, Network, Cloud (grouping is optional in Settings). +- **Folder pane** — details, list, or preview. Split pane is optional. +- **Queue** — compact status; expand for the full File Operations Queue. + +### Tabs and panes + +| Action | How | +| --- | --- | +| New tab | File → New tab, or `Ctrl+T` | +| Close tab | File → Close tab, or `Ctrl+W` | +| Split pane | File → Split pane | +| Details / List / Preview | View menu or toolbar | +| Refresh | View → Refresh, or `F5` | + +--- + +## Locations + +### This PC + +Local NTFS volumes and removable disks. Capacity and free space show next to size where Windows reports them. + +### Network + +Add a UNC path with **Tools → Locations → Add network…** (`\\server\share`). Mapped Windows drive letters can be imported when Workbench discovers them. Forgetting a Workbench location does **not** disconnect the Windows mapping. + +### Cloud + +OneDrive, Google Drive, and Nextcloud appear when you add their **mounted Windows folders** (**Tools → Locations → Add OneDrive…** / **Google Drive…** / **Nextcloud…**). Workbench browses those paths with Win32 like any other folder. Plugins only overlay status, pin/dehydrate actions, and quota. Cloud folders stay ordinary locations — they are not a separate “cloud filesystem.” + +Online-only placeholders are **not** hydrated to compute size, search content, hash duplicates, or pack archives. Status text on the item tells you when a file is online-only. + +### Recycle Bin + +Open it from **Tools → Recycle Bin**. Workbench talks to the real Windows Recycle Bin. Emptying it is a queued operation. `$RECYCLE.BIN` folders on volumes are hidden from normal browsing. + +### Remove vs restore + +- **Remove from Explorer** forgets the Workbench location and its index rows. +- Windows resources stay. You can import them again from discovery. + +--- + +## Browsing and file management + +The open folder is always the live filesystem when the location is online. Index data fills in folder sizes, search, and analysis. + +Large folders appear as soon as names are known. Size, date, and type from the directory listing show with the row. Cloud status, indexed folder totals, and Git badges fill in shortly after — blank cells mean that extra metadata has not arrived yet, not that the file is empty. Opening another folder cancels leftover work from the previous one. + +**Preview** shows a wrapping thumbnail grid. Only the tiles on screen (plus a small prefetch) are decoded, on background threads. Other files keep a generic icon until you scroll to them. Online-only cloud files are never opened just to make a thumbnail. Returning to a folder reuses thumbnails that are still in memory. + +Sorting by name or type happens once the listing is in. Sorting by size waits until indexed folder totals are applied, so rows do not jump on every update. Clicking a column sorts immediately with whatever is already known. + +Hidden files follow Settings. Protected system locations (`System Volume Information`, Recovery, pagefile, and similar) are hidden unless you turn them on. Recycle Bin folders stay hidden. Access-denied folders show as access denied — never as 0 bytes. + +| Shortcut | Action | +| --- | --- | +| `Alt+Left` / Back | Back | +| `Alt+Right` | Forward | +| `Alt+Up` | Up | +| `F5` | Refresh | +| `Enter` | Open | +| `F2` | Rename (single item, immediate) | +| `Ctrl+C` / `Ctrl+X` / `Ctrl+V` | Copy / Cut / Paste | +| `Delete` | Recycle (queued) | +| `Ctrl+T` / `Ctrl+W` | New tab / Close tab | + +Drag and drop copies by default. Hold `Shift` to move. Right-drag offers a menu. + +Hidden files follow Settings. Protected system locations (`System Volume Information`, Recovery, pagefile, and similar) are hidden unless you turn them on. Recycle Bin folders stay hidden. Access-denied folders show as access denied — never as 0 bytes. + +--- + +## Index and search + +Indexing is **user-triggered**, then kept current in the background: + +- Local NTFS: USN journal when Windows allows it; otherwise folder reconcile + watcher +- Network: scan + watcher (best effort) +- Archives: optional (Settings → include archive contents) + +Default excludes include Windows, recycle bins, `node_modules`, `.git`, and similar. Inaccessible paths are skipped. + +Search uses the index: name/glob plus size, type, and date filters. Results are paged (500, hard cap 10 000). Offline volumes stay searchable from the last index; the live folder listing still needs the volume. + +Archive hits can look like: + +`\\NAS\Archive\2019-backup.7z\Projects\README.md` + +even when that NAS is currently offline — if the archive was indexed earlier. + +--- + +## Storage analysis + +**Tools → Storage → Storage analysis** (or the toolbar). WinDirStat-style trees, biggest folders/files, by type, by source. Figures come from the index, so build the index first. + +--- + +## Duplicates + +**Tools → Storage → Duplicates**. Groups are hashed in the background (size → partial hash → full hash only when needed). Workbench distinguishes: + +| Class | Meaning | +| --- | --- | +| Accidental | Same content, no known reason | +| Synchronized | Created by Folder Sync | +| Intentional | You marked them | +| Hardlink | Same file id on the same volume | +| Backup | Reserved; not auto-tagged yet | + +Intentional and sync copies are hidden by default. Hardlinks are not wasted space. + +--- + +## File Operations Queue + +Almost every change goes through the queue instead of happening silently. + +Supported operations today: copy, move, recycle, permanent delete, rename, empty Recycle Bin, extract, compress, add to archive, verify archive. + +The queue: + +- Runs **one operation at a time** +- Can pause / resume / pause all +- Lets you reorder, remove, retry, and clear finished items +- Survives Workbench restarts +- Waits when the destination is unreachable (network share, USB) and continues when it returns +- Records append-only history +- Fails locked files so you can retry + +Auto-clear when done is a setting. Failed items stay until you dismiss or retry them. + +**Undo** exists for completed **rename batches**. Copy and move are not undone from the queue in this build. + +--- + +## Batch rename + +**Tools → File Operations → Batch rename…** (select items first). F2 stays a single immediate rename. + +Workflow: configure → preview → validate → queue. + +Rules: search/replace, regex, prefix, suffix, counter (with padding), case, extension. Collisions and illegal Windows names are caught before enqueue. Completed batches can be undone (**Tools → File Operations → Undo last rename batch**). + +Metadata placeholders such as `{CreatedDate}` or `{Width}` are not implemented yet. `{Counter}` and `{Extension}` work. + +--- + +## Archives + +Needs **7-Zip** on the machine (Settings can point at `7z.exe`; otherwise Program Files and PATH). 7-Zip is not bundled. + +| Action | Menu | +| --- | --- | +| Extract here / Extract to… | Tools → File Operations → Archives, or context menu | +| Compress to ZIP / 7z | Tools → File Operations → Archives, or context menu | +| Add to archive… | Tools → File Operations → Archives | +| Verify archive | Tools → File Operations → Archives | + +Jobs go through the queue. Online-only cloud archives are refused so Workbench will not hydrate them. Formats include ZIP, 7z, RAR, TAR and related containers through 7-Zip. + +--- + +## Folder sync + +**Tools → Automation → Folder sync…** — **one-way** only. + +| Mode | Behavior | +| --- | --- | +| Copy / Update | Add and overwrite from source. Never deletes. Destination-newer files are skipped with a warning. | +| Mirror | Also deletes destination items that are not in the source. Deletes stay in the preview until you Queue. Mirror AutoRun is disabled. | + +Copy / Update can AutoRun when the destination volume becomes available (USB, share). Drive letters may change; Workbench stores volume identity. Excludes are one glob per line. + +Files copied by sync are tagged as synchronized duplicates. + +--- + +## Operation profiles + +**Tools → Automation → Operation profiles…** — named recipes that **plan** work, then enqueue it. Steps never touch the filesystem themselves. + +Toggles (not a free-form graph): Copy, Rename, Compress, require a clean Git working tree. Excludes are globs, one per line. + +Built-in recipes (seeded when the list is empty): + +1. **Archive folder** — require clean Git, compress 7z, exclude `.git` / `bin` / `obj` / `.vs` +2. **Copy to destination** — copy; AutoRun when the destination volume connects + +Run from the window, from **Run profile** on the context menu (always previews first), or by dropping files onto a profile. AutoRun is Copy-only (no rename, no compress) and fires on unreachable → reachable, not on a timer while already online. + +Dirty or missing Git, missing 7-Zip, or an unreachable destination stops the plan. Nothing is queued. + +Not in this build: SHA-256, recycle source after success, FFmpeg, scheduled or folder-watcher triggers. + +--- + +## Organize folder + +**Tools → File Operations → Organize folder…** or **Organize this folder…** on a directory. + +Classification **suggests** moves. Nothing moves until you Preview and Queue. + +| Category | Typical destination | +| --- | --- | +| Photos / Video / Audio / Documents | Windows Pictures, Videos, Music, Documents | +| Installers | Folder you choose (for example Software) | +| Archives | Folder you choose | +| Git repositories | Folder you choose (Development) | +| Unknown, system data, backups, build output | Left in place | + +Build output names (`node_modules`, `bin`, `obj`, `.vs`, and similar) are never moved. Online-only cloud items are skipped. Old installers (older than one year) still propose a move and show a warning. Destinations may sit *inside* the source folder (Downloads → Downloads\Software). Destinations are remembered in preferences. + +Never auto-reorganizes. No MIME/content sniffing (that would hydrate cloud files). + +--- + +## Git + +Workbench detects repositories and shows a badge (branch, modified, untracked, ahead/behind). **Tools → Development → Open terminal here** and **Open in Cursor** are available when a folder is in context. + +Missing `git.exe` means no badge. Path can be set in Settings. Git is not bundled. There is no commit, push, pull, or diff viewer. Profiles can require a clean working tree. + +--- + +## Cloud overlays + +When a cloud folder is added: + +- Status text on items (available / online-only / syncing) +- **Always keep on this device** / **Free up space** when the provider supports pin/dehydrate +- Quota in capacity/free space where the provider reports it + +Workbench never starts a cloud vendor’s own two-way sync. It never hydrates a file as a side effect of browse, size, search, hash, or archive. + +--- + +## Settings + +**Settings** in the menu: + +- Dark / Light theme +- Group network under Network; group cloud under Cloud (independent) +- Show hidden files +- Show protected system locations +- Auto-clear queue when done +- Include archive contents in the index +- Path to 7-Zip +- Path to git.exe + +These options change what Workbench shows and indexes. They do not change Windows Explorer settings. + +--- + +## Help + +| Item | What you get | +| --- | --- | +| Documentation | This guide, shown inside Workbench | +| About | Version, data folder, log folder | + +The source of this guide is `docs/Documentation.md` in the project (or `Documentation.md` next to the executable). Edit the Markdown in any editor, then reopen this window. A copy is also embedded in the app if no file is found. + +Press `F1` to open Documentation. + +--- + +## What is not in this build + +Left open on purpose: + +- Two-way sync and conflict resolution UI +- Undo for copy/move +- Concurrent copies across different disks +- FFmpeg / media conversion +- Multi-PC search, sharing, encrypted vaults +- Robocopy as a second transfer engine +- Scheduled profiles and folder-watcher triggers +- MIME/EXIF classification +- Duplicate “backup copy” auto-tagging +- Rename placeholders from EXIF or dates + +--- + +## Definition of done + +Explorer Workbench is never finished. A feature is useful when it improves the actual workflow of the person using it. diff --git a/src/Explorer.Analysis/AnalysisService.cs b/src/Explorer.Analysis/AnalysisService.cs index 12b633f..7ccee98 100644 --- a/src/Explorer.Analysis/AnalysisService.cs +++ b/src/Explorer.Analysis/AnalysisService.cs @@ -88,6 +88,48 @@ public sealed class AnalysisService public Task> GetKnownSourcesAsync(CancellationToken cancellationToken = default) => RunOffUiAsync(ct => _store.Sources.GetAllAsync(ct), cancellationToken); + public Task> GetClassifiedDuplicatesAsync( + int take = 200, + CancellationToken cancellationToken = default) + => RunOffUiAsync(async ct => + { + var raw = await _store.Hashes.GetDuplicateGroupsAsync(null, null, Math.Max(take * 8, 400), ct) + .ConfigureAwait(false); + var ids = raw.SelectMany(g => g.Entries.Select(e => e.Id)).Distinct().ToList(); + var relations = await _store.Relations.GetAmongAsync(ids, ct).ConfigureAwait(false); + return (IReadOnlyList)raw + .Select(g => DuplicateClassifier.ClassifyGroup(g, DuplicateClassifier.RelationsFor(g.Entries, relations))) + .ToList(); + }, cancellationToken); + + public Task MarkDuplicateGroupAsync( + IReadOnlyList entries, + FileRelationKind kind, + CancellationToken cancellationToken = default) + => RunOffUiAsync(async ct => + { + var ids = entries.Select(e => e.Id).Distinct().ToList(); + await _store.Relations.DeleteAmongAsync( + ids, + [FileRelationKind.AccidentalDuplicate, FileRelationKind.IntentionalDuplicate], + ct) + .ConfigureAwait(false); + var utc = DateTimeOffset.UtcNow; + foreach (var (left, right) in DuplicateClassifier.Pairs(entries)) + { + await _store.Relations.UpsertAsync(new FileRelation + { + LeftEntryId = left, + RightEntryId = right, + Kind = kind, + Origin = FileRelationOrigin.User, + CreatedUtc = utc + }, ct).ConfigureAwait(false); + } + + return 0; + }, cancellationToken); + private async Task CachedAsync(string key, Func> query, CancellationToken cancellationToken) { await EnsureReadyAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Explorer.App/AboutWindow.xaml b/src/Explorer.App/AboutWindow.xaml new file mode 100644 index 0000000..5fcc36b --- /dev/null +++ b/src/Explorer.App/AboutWindow.xaml @@ -0,0 +1,32 @@ + + +