feat: skip local hashing for iCloud assets, use server-computed checksum

Instead of downloading iCloud assets twice (once to hash, once to upload),
skip local hashing for iCloud-only assets and let the server return its
computed SHA1 checksum in the upload response. The mobile app stores this
checksum locally to prevent re-uploads.

Changes:
- Server returns checksum in upload response (created + duplicate)
- iOS native layer tags iCloud-only assets with ICLOUD_ONLY error
- Hash service skips iCloud assets (allowNetworkAccess: false)
- Upload result carries server checksum back to mobile
- Foreground/background upload services store server checksum
- Backup candidates include unhashed assets (onlyHashed: false)

https://claude.ai/code/session_01LEs74WpkJ1gWcJrFBsp1i2
This commit is contained in:
Claude
2026-03-17 18:52:32 +00:00
parent 34caed3b2b
commit 1811d42d79
7 changed files with 51 additions and 8 deletions
+7 -1
View File
@@ -109,9 +109,11 @@ class HashService {
_log.fine("Hashing ${toHash.length} files");
final hashed = <String, String>{};
// Never download from iCloud just to hash. iCloud-only assets will be
// uploaded directly and the server will compute + return their checksum.
final hashResults = await _nativeSyncApi.hashAssets(
toHash.keys.toList(),
allowNetworkAccess: album.backupSelection == BackupSelection.selected,
allowNetworkAccess: false,
);
assert(
hashResults.length == toHash.length,
@@ -127,6 +129,10 @@ class HashService {
final hashResult = hashResults[i];
if (hashResult.hash != null) {
hashed[hashResult.assetId] = hashResult.hash!;
} else if (hashResult.error == 'ICLOUD_ONLY') {
// Asset is in iCloud and not available locally. It will be uploaded
// directly and the server will compute its checksum.
_log.fine("Skipping iCloud-only asset ${hashResult.assetId} from album: ${album.name}");
} else {
final asset = toHash[hashResult.assetId];
_log.warning(