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.
This commit is contained in:
Kyle Bolen
2026-07-28 06:56:15 +00:00
parent 617ce03cf9
commit 66378b4a02
3 changed files with 31 additions and 1 deletions

View File

@@ -88,6 +88,13 @@ To re-enable Image Capture later:
launchctl load -w /System/Library/LaunchAgents/com.apple.ptpcamera.plist 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 ### 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: If your iPhone is shooting in HEIC (the default), PhotoPhetch will warn you and convert to JPEG during import. To stop shooting HEIC:

View File

@@ -94,6 +94,15 @@ class IosConnector(
rawPhotos.add(photo) 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 // Detect Live Photo pairs: HEIC + MOV with the same base name and close timestamps
return tagLivePhotoPairs(rawPhotos) return tagLivePhotoPairs(rawPhotos)
} }

View File

@@ -51,8 +51,22 @@ fun DensePhotoGrid(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
if (folderSections.isEmpty() || folderSections.all { it.allPhotos.isEmpty() }) { if (folderSections.isEmpty() || folderSections.all { it.allPhotos.isEmpty() }) {
val isIos = folderSections.isEmpty() // IosConnector returns no folders when blocked
Box(modifier.fillMaxSize(), contentAlignment = Alignment.Center) { 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 return
} }