Skip to main content

max / audiofiles

ui: fix detail-panel desync, drop dead Linux drag-out affordance (ultra-fuzz) refresh_contents repulled the focused sample's tags but not its waveform or analysis, so changing the list (enter folder / search / sort) reset the cursor to a different row 0 while the detail panel still showed the previous sample's waveform and BPM/key grid. Repull the detail alongside the tags. Native drag-out had no Linux backend, so the "Drag to Finder or DAW" affordance did nothing and leaked a temp dir on each attempt. Gate the drag cfgs to macOS/Windows only (no dead affordance on Linux) and clean up the temp dir in begin_drag's fallback arm for any stray call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-06-19 20:58 UTC
Commit: db956d5eedcd9adde17a2aad3c74b0255fb43e29
Parent: d061494
4 files changed, +18 insertions, -9 deletions
@@ -160,6 +160,10 @@ pub fn begin_drag(files: &[DragFile]) -> bool {
160 160 }
161 161 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
162 162 {
163 + // No OS drag backend on this platform. The UI no longer offers drag-out
164 + // here, but begin_drag is public, so clean up the temp dir prepare_files
165 + // created rather than leaking it on any stray call.
166 + cleanup_drag_dir();
163 167 DRAG_ACTIVE.store(false, Ordering::Release);
164 168 false
165 169 }
@@ -72,6 +72,11 @@ impl BrowserState {
72 72 }
73 73
74 74 self.refresh_selected_tags();
75 + // Refresh the detail panel too: changing the list (folder/search/sort)
76 + // resets the cursor to row 0, a different sample than before, so the
77 + // cached waveform/analysis must be repulled alongside the tags or the
78 + // detail panel renders the new row's name over the old sample's data.
79 + self.refresh_selected_detail();
75 80 self.mark_mirror_dirty();
76 81 }
77 82
@@ -11,7 +11,7 @@ use super::instrument_panel::DragPayload;
11 11 use super::theme;
12 12 use super::widgets;
13 13
14 - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))]
14 + #[cfg(any(target_os = "macos", target_os = "windows"))]
15 15 use super::file_list_menus::start_os_drag;
16 16
17 17 /// Draw the sortable, multi-column file list.
@@ -24,7 +24,7 @@ pub fn draw_file_list(
24 24 // mouse-up so egui's pointer state is stale (`resp.dragged()` stays true).
25 25 // Block new OS drags until egui sees the pointer released or a 2s safety
26 26 // timeout expires.
27 - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))]
27 + #[cfg(any(target_os = "macos", target_os = "windows"))]
28 28 let os_drag_blocked = if let Some(t) = state.os_drag_cooldown {
29 29 let pointer_up = !ui.input(|i| i.pointer.button_down(egui::PointerButton::Primary));
30 30 if pointer_up || t.elapsed() > std::time::Duration::from_secs(2) {
@@ -326,9 +326,9 @@ pub fn draw_file_list(
326 326
327 327 // Name (with inline icon)
328 328 row.col(|ui| {
329 - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))]
329 + #[cfg(any(target_os = "macos", target_os = "windows"))]
330 330 let drag_blocked = os_drag_blocked;
331 - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
331 + #[cfg(not(any(target_os = "macos", target_os = "windows")))]
332 332 let drag_blocked = false;
333 333 draw_name_column(ui, state, node, row_idx, selected, drag_blocked, sync_manager);
334 334 });
@@ -468,7 +468,7 @@ fn draw_name_column(
468 468 // While the post-drag cooldown is active, surface the wait state in the
469 469 // hover text — an invisible 2-second lockout otherwise reads as the app
470 470 // having silently stopped responding.
471 - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))]
471 + #[cfg(any(target_os = "macos", target_os = "windows"))]
472 472 let resp = if !node.cloud_only && node.node.node_type == NodeType::Sample {
473 473 let hover = if os_drag_blocked {
474 474 "Just dragged — ready again in a moment."
@@ -514,7 +514,7 @@ fn draw_name_column(
514 514 }
515 515
516 516 // Native OS drag-out to Finder/DAW (only when instrument panel is closed)
517 - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))]
517 + #[cfg(any(target_os = "macos", target_os = "windows"))]
518 518 if !os_drag_blocked
519 519 && !state.instrument_visible
520 520 && node.node.node_type == NodeType::Sample
@@ -530,7 +530,7 @@ fn draw_name_column(
530 530 // Trace when the post-drag cooldown swallows a user's drag attempt. The
531 531 // hover-text change above is the user-visible signal; this log helps
532 532 // diagnose any lingering drag-pipeline bugs that hide behind the cooldown.
533 - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))]
533 + #[cfg(any(target_os = "macos", target_os = "windows"))]
534 534 if os_drag_blocked
535 535 && node.node.node_type == NodeType::Sample
536 536 && !node.cloud_only
@@ -8,7 +8,7 @@ use audiofiles_core::vfs::NodeType;
8 8 use super::theme;
9 9 use super::widgets;
10 10
11 - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))]
11 + #[cfg(any(target_os = "macos", target_os = "windows"))]
12 12 use crate::drag_out;
13 13
14 14 /// Draw the right-click context menu for a single item.
@@ -439,7 +439,7 @@ fn truncate_name(name: &str, max_len: usize) -> String {
439 439 }
440 440 }
441 441
442 - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))]
442 + #[cfg(any(target_os = "macos", target_os = "windows"))]
443 443 pub fn start_os_drag(state: &mut BrowserState) {
444 444 let nodes = state.selected_nodes();
445 445 let files: Vec<drag_out::DragFile> = nodes