Fix EXIF verification for non-Apple devices + sticky preserve folder

EXIF verification: any non-blank Make is now considered verified.
Only absent/empty Make triggers 'Origin unknown' warning. Samsung,
Google, etc. are all legitimate camera makes.
Also cache exifMake to avoid calling exiftool twice per file.

Preserve folder structure: add defaultPreserveFolderStructure to
AppConfig. Toggling in ImportScreen saves it as the new default.
prepareImport() reads from config instead of always resetting to true.
This commit is contained in:
Kyle Bolen
2026-07-30 12:48:15 +00:00
parent a8906fa265
commit dc32a3a3d7
4 changed files with 17 additions and 8 deletions

View File

@@ -17,6 +17,8 @@ data class AppConfig(
val defaultStripLivePhotoMotion: Boolean = true,
/** Default: do not delete from phone (safer default) */
val defaultDeleteAfterVerify: Boolean = false,
/** Default: preserve folder structure on import */
val defaultPreserveFolderStructure: Boolean = true,
/** Whether the user has been warned about HEIC phone settings */
val heicWarningDismissed: Boolean = false,
/** Path to adb binary, or null to use PATH */

View File

@@ -154,6 +154,8 @@ class Copier(
}
}
val exifMake = readExifMake(finalFile)
CopyResult(
photo = photo,
destinationPath = finalFile,
@@ -161,11 +163,8 @@ class Copier(
destSha256 = destHash,
verified = verified,
convertedFromHeic = wasConverted,
exifVerified = readExifMake(finalFile)?.let { make ->
make.contains("apple", ignoreCase = true) ||
make.contains(photo.exifMake ?: "apple", ignoreCase = true)
},
exifMake = readExifMake(finalFile),
exifVerified = exifMake?.let { it.isNotBlank() },
exifMake = exifMake,
error = when {
!verified && remoteHash != null -> "Hash mismatch — file may be corrupt"
!verified -> "Copy failed — file missing or size mismatch"

View File

@@ -371,11 +371,11 @@ class AppState(private val configStore: ConfigStore) {
StagingPath.uniqueFolderName(Paths.get(cfg.stagingRoot), baseName)
} else baseName
// Multi-folder selection → preserve structure by default
// Multi-folder selection → preserve structure; otherwise use saved config default
val multipleSourceFolders = _selectedPhotos.value.map { it.sourceFolder }.distinct().size > 1
_importConfig.update { it.copy(
folderName = folderName,
preserveFolderStructure = multipleSourceFolders,
preserveFolderStructure = if (multipleSourceFolders) true else cfg.defaultPreserveFolderStructure,
) }
navigateTo(Screen.IMPORT_CONFIG)
}
@@ -469,6 +469,11 @@ class AppState(private val configStore: ConfigStore) {
saveConfig()
}
fun updateDefaultPreserveFolderStructure(value: Boolean) {
_config.update { it.copy(defaultPreserveFolderStructure = value) }
saveConfig()
}
fun dismissHeicWarning() {
_config.update { it.copy(heicWarningDismissed = true) }
saveConfig()

View File

@@ -154,7 +154,10 @@ fun ImportScreen(state: AppState) {
label = "Preserve folder structure",
description = "Files go into subfolders matching their source (Camera/, Screenshots/, etc.).",
checked = importConfig.preserveFolderStructure,
onCheckedChange = { state.updateImportConfig { copy(preserveFolderStructure = it) } },
onCheckedChange = {
state.updateImportConfig { copy(preserveFolderStructure = it) }
state.updateDefaultPreserveFolderStructure(it)
},
)
ToggleRow(
label = "Delete from phone after verification",