|
76 | 76 | getSelfDragFileInfos, |
77 | 77 | endSelfDragSession, |
78 | 78 | } from '../drag/drag-drop' |
| 79 | + import { initIndexEvents, prioritizeDir, cancelNavPriority } from '$lib/indexing/index' |
79 | 80 | import { resolveDropTarget } from '../drag/drop-target-hit-testing' |
80 | 81 | import DragOverlay from '../drag/DragOverlay.svelte' |
81 | 82 | import { showOverlay, updateOverlay, hideOverlay, type OverlayFileInfo } from '../drag/drag-overlay.svelte.js' |
|
118 | 119 | let unlistenDragDrop: UnlistenFn | undefined |
119 | 120 | let unlistenDragImageSize: UnlistenFn | undefined |
120 | 121 | let unlistenDragModifiers: UnlistenFn | undefined |
| 122 | + let unlistenIndexEvents: UnlistenFn | undefined |
121 | 123 |
|
122 | 124 | // Drag image size from the source app (macOS only, via swizzle). |
123 | 125 | // If the source provides a large preview (like Finder), we suppress our overlay. |
|
275 | 277 | // --- Unified handler functions --- |
276 | 278 |
|
277 | 279 | function handlePathChange(pane: 'left' | 'right', path: string) { |
| 280 | + const oldPath = getPanePath(pane) |
278 | 281 | setPanePath(pane, path) |
279 | 282 | setPaneHistory(pane, pushPath(getPaneHistory(pane), path)) |
280 | 283 | void saveAppStatus({ [paneKey(pane, 'path')]: path }) |
281 | 284 | void saveLastUsedPathForVolume(getPaneVolumeId(pane), path) |
| 285 | +
|
| 286 | + // Update index priorities: cancel old dir, prioritize new dir |
| 287 | + if (oldPath !== path) { |
| 288 | + void cancelNavPriority(oldPath) |
| 289 | + void prioritizeDir(path, 'current_dir') |
| 290 | + } |
| 291 | +
|
282 | 292 | containerElement?.focus() |
283 | 293 | } |
284 | 294 |
|
|
331 | 341 | volumePath: string, |
332 | 342 | targetPath: string, |
333 | 343 | ) { |
334 | | - void saveLastUsedPathForVolume(getPaneVolumeId(pane), getPanePath(pane)) |
| 344 | + const oldPath = getPanePath(pane) |
| 345 | + void saveLastUsedPathForVolume(getPaneVolumeId(pane), oldPath) |
335 | 346 |
|
336 | 347 | if (!volumes.find((v) => v.id === volumeId)) { |
337 | 348 | volumes = await listVolumes() |
|
343 | 354 | otherPanePath: getPanePath(other), |
344 | 355 | }) |
345 | 356 |
|
| 357 | + // Update index priorities: cancel old dir, prioritize new dir |
| 358 | + void cancelNavPriority(oldPath) |
| 359 | + void prioritizeDir(pathToNavigate, 'current_dir') |
| 360 | +
|
346 | 361 | setPaneVolumeId(pane, volumeId) |
347 | 362 | setPanePath(pane, pathToNavigate) |
348 | 363 | setPaneHistory(pane, push(getPaneHistory(pane), { volumeId, path: pathToNavigate })) |
|
652 | 667 | dropTargetFolderEl = null |
653 | 668 | } |
654 | 669 |
|
| 670 | + /** Ensures a path ends with '/' for correct prefix matching. */ |
| 671 | + function ensureTrailingSlash(path: string): string { |
| 672 | + return path.endsWith('/') ? path : path + '/' |
| 673 | + } |
| 674 | +
|
| 675 | + /** Called when the drive index updates directory stats. Re-fetches panes whose visible entries changed. */ |
| 676 | + function handleIndexDirUpdated(paths: string[]) { |
| 677 | + const leftDir = ensureTrailingSlash(leftPath) |
| 678 | + const rightDir = ensureTrailingSlash(rightPath) |
| 679 | +
|
| 680 | + let refreshLeft = false |
| 681 | + let refreshRight = false |
| 682 | +
|
| 683 | + for (const updatedPath of paths) { |
| 684 | + // An updated path is relevant if it is a direct child or deeper descendant |
| 685 | + // whose parent is displayed in the pane's current directory. |
| 686 | + // We check if parentOf(updatedPath) === panePath (i.e. the updated path itself |
| 687 | + // is a direct child entry visible in the listing). |
| 688 | + const updatedWithSlash = ensureTrailingSlash(updatedPath) |
| 689 | + if (!refreshLeft && updatedWithSlash.startsWith(leftDir) && updatedWithSlash !== leftDir) { |
| 690 | + refreshLeft = true |
| 691 | + } |
| 692 | + if (!refreshRight && updatedWithSlash.startsWith(rightDir) && updatedWithSlash !== rightDir) { |
| 693 | + refreshRight = true |
| 694 | + } |
| 695 | + if (refreshLeft && refreshRight) break |
| 696 | + } |
| 697 | +
|
| 698 | + if (refreshLeft) { |
| 699 | + // eslint-disable-next-line @typescript-eslint/no-unsafe-call |
| 700 | + leftPaneRef?.refreshView?.() |
| 701 | + } |
| 702 | + if (refreshRight) { |
| 703 | + // eslint-disable-next-line @typescript-eslint/no-unsafe-call |
| 704 | + rightPaneRef?.refreshView?.() |
| 705 | + } |
| 706 | + } |
| 707 | +
|
655 | 708 | function handleResizeForDevTools() { |
656 | 709 | void recalculateWebviewOffset() |
657 | 710 | } |
|
780 | 833 | setAltHeld(event.payload.altHeld) |
781 | 834 | }) |
782 | 835 |
|
| 836 | + // Listen for index directory updates to refresh panes when sizes change |
| 837 | + unlistenIndexEvents = await initIndexEvents(handleIndexDirUpdated) |
| 838 | +
|
| 839 | + // Prioritize scanning the initial directories of both panes |
| 840 | + void prioritizeDir(leftPath, 'current_dir') |
| 841 | + void prioritizeDir(rightPath, 'current_dir') |
| 842 | +
|
783 | 843 | // Register drag-and-drop target handler for external and pane-to-pane drops |
784 | 844 | unlistenDragDrop = await getCurrentWebview().onDragDropEvent((event) => { |
785 | 845 | const { type } = event.payload |
|
844 | 904 | newHistory: NavigationHistory, |
845 | 905 | targetPath: string, |
846 | 906 | ) { |
| 907 | + const oldPath = getPanePath(pane) |
847 | 908 | const entry = getCurrentEntry(newHistory) |
848 | 909 | const paneRef = getPaneRef(pane) |
849 | 910 |
|
| 911 | + // Update index priorities: cancel old dir, prioritize new dir |
| 912 | + if (oldPath !== targetPath) { |
| 913 | + void cancelNavPriority(oldPath) |
| 914 | + void prioritizeDir(targetPath, 'current_dir') |
| 915 | + } |
| 916 | +
|
850 | 917 | setPaneHistory(pane, newHistory) |
851 | 918 | setPanePath(pane, targetPath) |
852 | 919 | if (entry.volumeId !== getPaneVolumeId(pane)) { |
|
907 | 974 | unlistenDragImageSize?.() |
908 | 975 | unlistenDragModifiers?.() |
909 | 976 | unlistenDragDrop?.() |
| 977 | + unlistenIndexEvents?.() |
910 | 978 | cleanupNetworkDiscovery() |
911 | 979 | stopModifierTracking() |
912 | 980 | window.removeEventListener('resize', handleResizeForDevTools) // No-op in non-dev, safe to always call |
|
0 commit comments