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:
@@ -17,6 +17,8 @@ data class AppConfig(
|
|||||||
val defaultStripLivePhotoMotion: Boolean = true,
|
val defaultStripLivePhotoMotion: Boolean = true,
|
||||||
/** Default: do not delete from phone (safer default) */
|
/** Default: do not delete from phone (safer default) */
|
||||||
val defaultDeleteAfterVerify: Boolean = false,
|
val defaultDeleteAfterVerify: Boolean = false,
|
||||||
|
/** Default: preserve folder structure on import */
|
||||||
|
val defaultPreserveFolderStructure: Boolean = true,
|
||||||
/** Whether the user has been warned about HEIC phone settings */
|
/** Whether the user has been warned about HEIC phone settings */
|
||||||
val heicWarningDismissed: Boolean = false,
|
val heicWarningDismissed: Boolean = false,
|
||||||
/** Path to adb binary, or null to use PATH */
|
/** Path to adb binary, or null to use PATH */
|
||||||
|
|||||||
@@ -154,6 +154,8 @@ class Copier(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val exifMake = readExifMake(finalFile)
|
||||||
|
|
||||||
CopyResult(
|
CopyResult(
|
||||||
photo = photo,
|
photo = photo,
|
||||||
destinationPath = finalFile,
|
destinationPath = finalFile,
|
||||||
@@ -161,11 +163,8 @@ class Copier(
|
|||||||
destSha256 = destHash,
|
destSha256 = destHash,
|
||||||
verified = verified,
|
verified = verified,
|
||||||
convertedFromHeic = wasConverted,
|
convertedFromHeic = wasConverted,
|
||||||
exifVerified = readExifMake(finalFile)?.let { make ->
|
exifVerified = exifMake?.let { it.isNotBlank() },
|
||||||
make.contains("apple", ignoreCase = true) ||
|
exifMake = exifMake,
|
||||||
make.contains(photo.exifMake ?: "apple", ignoreCase = true)
|
|
||||||
},
|
|
||||||
exifMake = readExifMake(finalFile),
|
|
||||||
error = when {
|
error = when {
|
||||||
!verified && remoteHash != null -> "Hash mismatch — file may be corrupt"
|
!verified && remoteHash != null -> "Hash mismatch — file may be corrupt"
|
||||||
!verified -> "Copy failed — file missing or size mismatch"
|
!verified -> "Copy failed — file missing or size mismatch"
|
||||||
|
|||||||
@@ -371,11 +371,11 @@ class AppState(private val configStore: ConfigStore) {
|
|||||||
StagingPath.uniqueFolderName(Paths.get(cfg.stagingRoot), baseName)
|
StagingPath.uniqueFolderName(Paths.get(cfg.stagingRoot), baseName)
|
||||||
} else 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
|
val multipleSourceFolders = _selectedPhotos.value.map { it.sourceFolder }.distinct().size > 1
|
||||||
_importConfig.update { it.copy(
|
_importConfig.update { it.copy(
|
||||||
folderName = folderName,
|
folderName = folderName,
|
||||||
preserveFolderStructure = multipleSourceFolders,
|
preserveFolderStructure = if (multipleSourceFolders) true else cfg.defaultPreserveFolderStructure,
|
||||||
) }
|
) }
|
||||||
navigateTo(Screen.IMPORT_CONFIG)
|
navigateTo(Screen.IMPORT_CONFIG)
|
||||||
}
|
}
|
||||||
@@ -469,6 +469,11 @@ class AppState(private val configStore: ConfigStore) {
|
|||||||
saveConfig()
|
saveConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateDefaultPreserveFolderStructure(value: Boolean) {
|
||||||
|
_config.update { it.copy(defaultPreserveFolderStructure = value) }
|
||||||
|
saveConfig()
|
||||||
|
}
|
||||||
|
|
||||||
fun dismissHeicWarning() {
|
fun dismissHeicWarning() {
|
||||||
_config.update { it.copy(heicWarningDismissed = true) }
|
_config.update { it.copy(heicWarningDismissed = true) }
|
||||||
saveConfig()
|
saveConfig()
|
||||||
|
|||||||
@@ -154,7 +154,10 @@ fun ImportScreen(state: AppState) {
|
|||||||
label = "Preserve folder structure",
|
label = "Preserve folder structure",
|
||||||
description = "Files go into subfolders matching their source (Camera/, Screenshots/, etc.).",
|
description = "Files go into subfolders matching their source (Camera/, Screenshots/, etc.).",
|
||||||
checked = importConfig.preserveFolderStructure,
|
checked = importConfig.preserveFolderStructure,
|
||||||
onCheckedChange = { state.updateImportConfig { copy(preserveFolderStructure = it) } },
|
onCheckedChange = {
|
||||||
|
state.updateImportConfig { copy(preserveFolderStructure = it) }
|
||||||
|
state.updateDefaultPreserveFolderStructure(it)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
ToggleRow(
|
ToggleRow(
|
||||||
label = "Delete from phone after verification",
|
label = "Delete from phone after verification",
|
||||||
|
|||||||
Reference in New Issue
Block a user