@@ -438,6 +438,135 @@ impl MtpConnectionManager {
438438 . collect ( )
439439 }
440440
441+ /// Handles a StoreAdded event: queries the new storage, registers its volume,
442+ /// and broadcasts the change so the frontend picks it up.
443+ pub async fn handle_storage_added ( & self , device_id : & str , storage_id : u32 , app : & AppHandle ) {
444+ let device_arc = {
445+ let devices = self . devices . lock ( ) . await ;
446+ match devices. get ( device_id) {
447+ Some ( entry) => {
448+ // Skip if we already know about this storage (duplicate event)
449+ if entry. storages . iter ( ) . any ( |s| s. id == storage_id) {
450+ debug ! ( "handle_storage_added: storage {} already registered for {}" , storage_id, device_id) ;
451+ return ;
452+ }
453+ entry. device . clone ( )
454+ }
455+ None => {
456+ warn ! ( "handle_storage_added: device {} not in registry" , device_id) ;
457+ return ;
458+ }
459+ }
460+ } ;
461+
462+ // Query the new storage from the device
463+ let device = match acquire_device_lock ( & device_arc, device_id, "handle_storage_added" ) . await {
464+ Ok ( d) => d,
465+ Err ( e) => {
466+ warn ! ( "handle_storage_added: failed to acquire lock: {:?}" , e) ;
467+ return ;
468+ }
469+ } ;
470+
471+ let mtp_storage_id = mtp_rs:: ptp:: StorageId ( storage_id) ;
472+ let storage = match device. storage ( mtp_storage_id) . await {
473+ Ok ( s) => s,
474+ Err ( e) => {
475+ warn ! ( "handle_storage_added: failed to query storage {}: {:?}" , storage_id, e) ;
476+ return ;
477+ }
478+ } ;
479+
480+ let info = storage. info ( ) ;
481+ let device_supports_write = device. device_info ( ) . supports_operation ( OperationCode :: SendObjectInfo ) ;
482+ let storage_reports_read_only = !matches ! ( info. access_capability, mtp_rs:: ptp:: AccessCapability :: ReadWrite ) ;
483+
484+ let is_read_only = if !device_supports_write || storage_reports_read_only {
485+ true
486+ } else {
487+ let probe_ok = probe_write_capability ( & storage, & info. description ) . await ;
488+ if !probe_ok {
489+ info ! (
490+ "Storage '{}' claims write support but probe failed - marking read-only" ,
491+ info. description
492+ ) ;
493+ }
494+ !probe_ok
495+ } ;
496+
497+ let storage_info = MtpStorageInfo {
498+ id : storage_id,
499+ name : info. description . clone ( ) ,
500+ total_bytes : info. max_capacity ,
501+ available_bytes : info. free_space_bytes ,
502+ storage_type : Some ( format ! ( "{:?}" , info. storage_type) ) ,
503+ is_read_only,
504+ } ;
505+
506+ info ! (
507+ "Registering late-arriving storage '{}' (id={}) for device {}" ,
508+ storage_info. name, storage_id, device_id
509+ ) ;
510+
511+ // Release device lock before updating registry
512+ drop ( device) ;
513+
514+ // Register the volume
515+ let volume_id = format ! ( "{}:{}" , device_id, storage_id) ;
516+ let volume = Arc :: new ( MtpVolume :: new ( device_id, storage_id, & storage_info. name ) ) ;
517+ get_volume_manager ( ) . register ( & volume_id, volume) ;
518+
519+ // Update the DeviceEntry's storage list
520+ {
521+ let mut devices = self . devices . lock ( ) . await ;
522+ if let Some ( entry) = devices. get_mut ( device_id) {
523+ entry. storages . push ( storage_info. clone ( ) ) ;
524+ }
525+ }
526+
527+ // Emit updated device info so the frontend knows about the new storage
528+ let _ = app. emit (
529+ "mtp-device-connected" ,
530+ serde_json:: json!( {
531+ "deviceId" : device_id,
532+ "deviceName" : "" ,
533+ "storages" : [ storage_info]
534+ } ) ,
535+ ) ;
536+
537+ // Broadcast volume list change
538+ crate :: volume_broadcast:: emit_volumes_changed ( ) ;
539+ }
540+
541+ /// Handles a StoreRemoved event: unregisters the volume and broadcasts the change.
542+ pub async fn handle_storage_removed ( & self , device_id : & str , storage_id : u32 , app : & AppHandle ) {
543+ let volume_id = format ! ( "{}:{}" , device_id, storage_id) ;
544+
545+ // Remove from DeviceEntry
546+ {
547+ let mut devices = self . devices . lock ( ) . await ;
548+ if let Some ( entry) = devices. get_mut ( device_id) {
549+ entry. storages . retain ( |s| s. id != storage_id) ;
550+ }
551+ }
552+
553+ // Unregister the volume
554+ get_volume_manager ( ) . unregister ( & volume_id) ;
555+ info ! ( "Unregistered MTP volume: {} (storage removed)" , volume_id) ;
556+
557+ // Emit event so frontend updates
558+ let _ = app. emit (
559+ "mtp-storage-removed" ,
560+ serde_json:: json!( {
561+ "deviceId" : device_id,
562+ "storageId" : storage_id
563+ } ) ,
564+ ) ;
565+
566+ // Broadcast volume list change
567+ crate :: volume_broadcast:: emit_volumes_changed ( ) ;
568+ }
569+
441570 /// Queries live storage space from the device and updates the cache.
442571 ///
443572 /// Returns `(total_bytes, available_bytes)` freshly read from the device,
0 commit comments