From 66378b4a02879a4a91bfdc3707342609e45b9c2f Mon Sep 17 00:00:00 2001 From: Kyle Bolen Date: Tue, 28 Jul 2026 06:56:15 +0000 Subject: [PATCH] Document and handle USB conflict between iPhone and Android in Charging mode IosConnector: add comment explaining 0-folders causes. DensePhotoGrid: show actionable hint when no photos found (unlock screen, switch Android to File Transfer, killall PTPCamera). README: add 'Using iPhone and Android at the same time' section. --- README.md | 7 +++++++ .../bolenpad/photophetch/device/IosConnector.kt | 9 +++++++++ .../bolenpad/photophetch/ui/DensePhotoGrid.kt | 16 +++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 230accf..e94d40f 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,13 @@ To re-enable Image Capture later: launchctl load -w /System/Library/LaunchAgents/com.apple.ptpcamera.plist ``` +### Using iPhone and Android at the same time + +If you have both phones plugged in, the Android phone must be in **Transferring files** mode (not Charging only). An Android phone in Charging mode can block macOS USB enumeration and cause gphoto2 to see 0 folders on the iPhone. Either: + +- Switch the Android to **Transferring files** mode from its notification shade, or +- Unplug the Android while working with the iPhone + ### HEIC settings If your iPhone is shooting in HEIC (the default), PhotoPhetch will warn you and convert to JPEG during import. To stop shooting HEIC: diff --git a/src/main/kotlin/com/bolenpad/photophetch/device/IosConnector.kt b/src/main/kotlin/com/bolenpad/photophetch/device/IosConnector.kt index 1f373e3..cf13662 100644 --- a/src/main/kotlin/com/bolenpad/photophetch/device/IosConnector.kt +++ b/src/main/kotlin/com/bolenpad/photophetch/device/IosConnector.kt @@ -94,6 +94,15 @@ class IosConnector( rawPhotos.add(photo) } + if (rawPhotos.isEmpty()) { + // gphoto2 connected but found no files. Common causes: + // 1. iPhone screen is locked — unlock and retry + // 2. Another USB device (e.g. Android phone in Charging mode) is blocking + // USB enumeration — unplug other devices or switch Android to File Transfer mode + // 3. PTPCamera daemon grabbed the device — run: killall PTPCamera + // We return empty and let the UI show the no-photos state with a hint. + } + // Detect Live Photo pairs: HEIC + MOV with the same base name and close timestamps return tagLivePhotoPairs(rawPhotos) } diff --git a/src/main/kotlin/com/bolenpad/photophetch/ui/DensePhotoGrid.kt b/src/main/kotlin/com/bolenpad/photophetch/ui/DensePhotoGrid.kt index 123c4e6..63bf13e 100644 --- a/src/main/kotlin/com/bolenpad/photophetch/ui/DensePhotoGrid.kt +++ b/src/main/kotlin/com/bolenpad/photophetch/ui/DensePhotoGrid.kt @@ -51,8 +51,22 @@ fun DensePhotoGrid( modifier: Modifier = Modifier, ) { if (folderSections.isEmpty() || folderSections.all { it.allPhotos.isEmpty() }) { + val isIos = folderSections.isEmpty() // IosConnector returns no folders when blocked Box(modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - Text("No photos", color = MaterialTheme.colorScheme.onSurfaceVariant) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.padding(32.dp), + ) { + Text("No photos found", style = MaterialTheme.typography.titleMedium) + Text( + "• Make sure the iPhone screen is unlocked\n" + + "• If another phone is plugged in, switch it to \"Transferring files\" mode\n" + + "• Run: killall PTPCamera", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } } return }