Skip to content

Commit d37b8a5

Browse files
committed
Bugfix: Fix MTP browsing and device name
- Fix panic in `MtpVolume::list_directory`: the cancellation-aware `std::thread::spawn` in `streaming.rs` had no Tokio runtime context, so `Handle::current()` panicked. Pass the runtime handle into the thread via `handle.enter()`. - Show device name ("Pixel 9 Pro XL") instead of storage name ("Internal shared storage") for single-storage MTP devices in the volume picker.
1 parent f166b06 commit d37b8a5

3 files changed

Lines changed: 14 additions & 7 deletions

File tree

apps/desktop/src-tauri/src/file_system/listing/streaming.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,14 @@ fn read_directory_with_progress(
271271
let app_for_progress = app.clone();
272272
let listing_id_for_progress = listing_id.to_string();
273273

274+
// Capture the Tokio runtime handle so the spawned thread can access it.
275+
// This is needed for MTP volumes, which use `Handle::block_on` internally.
276+
let runtime_handle = tokio::runtime::Handle::current();
277+
274278
std::thread::spawn(move || {
279+
// Enter the Tokio runtime context so `Handle::current()` works inside volumes
280+
let _guard = runtime_handle.enter();
281+
275282
let on_progress = |loaded_count: usize| {
276283
use tauri::Emitter;
277284
let _ = app_for_progress.emit(

apps/desktop/src/lib/mtp/mtp-store.svelte.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ export interface MtpVolume {
402402
deviceId: string
403403
/** Storage ID */
404404
storageId: number
405-
/** Display name: "{DeviceName} - {StorageName}" or just storage name if device has one storage */
405+
/** Display name: "{DeviceName} - {StorageName}" for multi-storage, or just device name for single storage */
406406
name: string
407407
/** Virtual path: "mtp://{deviceId}/{storageId}" */
408408
path: string
@@ -423,11 +423,11 @@ export function getMtpVolumes(): MtpVolume[] {
423423
for (const deviceState of state.devices.values()) {
424424
if (deviceState.connectionState === 'connected' && deviceState.storages.length > 0) {
425425
// Connected device with storages: create one volume per storage
426-
const showDeviceName = deviceState.storages.length > 1
426+
const hasMultipleStorages = deviceState.storages.length > 1
427427
for (const storage of deviceState.storages) {
428-
const volumeName = showDeviceName
428+
const volumeName = hasMultipleStorages
429429
? `${deviceState.displayName} - ${storage.name}`
430-
: storage.name || deviceState.displayName
430+
: deviceState.displayName || storage.name
431431

432432
volumes.push({
433433
id: `${deviceState.device.id}:${String(storage.id)}`,

apps/desktop/src/lib/mtp/mtp-store.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ describe('mtp-store', () => {
431431
expect(volumes[0].isReadOnly).toBe(true)
432432
})
433433

434-
it('uses storage name only for single storage device', async () => {
434+
it('uses device name for single storage device', async () => {
435435
vi.mocked(listMtpDevices).mockResolvedValue([mockDevice])
436436
vi.mocked(connectMtpDevice).mockResolvedValue(mockConnectedInfo)
437437
const { scanDevices, connect, getMtpVolumes } = await loadModule()
@@ -441,8 +441,8 @@ describe('mtp-store', () => {
441441

442442
const volumes = getMtpVolumes()
443443
expect(volumes).toHaveLength(1)
444-
// Single storage: use storage name, not "Device - Storage"
445-
expect(volumes[0].name).toBe('Internal shared storage')
444+
// Single storage: use device name, not storage name
445+
expect(volumes[0].name).toBe('Pixel 8')
446446
})
447447
})
448448

0 commit comments

Comments
 (0)