rotateImageByHash<DataT extends Data> method
Future<String?>
rotateImageByHash<DataT extends Data>( - DataT? data,
- String hash, {
- int quarterTurns = 1,
- Data? caller,
- bool forceUpdate = false,
})
Implementation
Future<String?> rotateImageByHash<DataT extends Data>(
DataT? data,
String hash, {
int quarterTurns = 1,
Data? caller,
bool forceUpdate = false,
}) async {
try {
if (data == null) return 'no data to rotate';
var turns = quarterTurns % 4;
if (turns < 0) turns += 4;
if (turns == 0) return 'rotation unchanged';
final requested = hash.trim();
if (requested.isEmpty) return 'no image selected';
final scope = local.scopeFor(data, caller: caller).trim();
File? sourceFile = await resolveImageFileByHash(requested, scope: scope);
if (sourceFile == null && !_isLocalImageReference(requested)) {
final mapped = await lookupImageNameForHash(requested, scope: scope);
if (mapped != null && mapped.trim().isNotEmpty) {
sourceFile =
await resolveImageFileByHash(mapped.trim(), scope: scope);
}
}
if (sourceFile == null) {
return 'image not found locally';
}
final originalBytes = await sourceFile.readAsBytes();
final decoded = imglib.decodeImage(originalBytes);
if (decoded == null) return 'could not decode image';
final rotated = imglib.copyRotate(decoded, angle: 90 * turns);
final rotatedBytes =
_encodeRotatedImageBytes(rotated, sourceFile.path.toLowerCase());
// Local-only image refs (timestamp/scoped/local prefixes) are uploaded by
// pending multipart requests. Overwrite the file in place so sync uploads
// the rotated bytes.
if (_isLocalImageReference(requested)) {
await sourceFile.writeAsBytes(rotatedBytes, flush: true);
await FileImage(sourceFile).evict();
return 'image rotated locally';
}
// Backend hash: create a rotated replacement image, upload it, then remove
// the old hash so backend and local state stay in sync.
final oldRefs = _collectImageRefs(data);
final wasMainImage = data.mainhash == requested;
final newScopedName = await _nextScopedImageName(scope);
final rotatedFile = await storeImage(rotatedBytes, newScopedName);
if (rotatedFile == null) return 'could not persist rotated image';
await FileImage(rotatedFile).evict();
final uploadResult = await uploadNewImagesOrFiles<DataT>(
data,
[XFile(rotatedFile.path)],
caller: caller,
forceUpdate: forceUpdate,
);
final newRefs = _collectImageRefs(data);
final addedRefs = newRefs.difference(oldRefs);
final replacementRef = addedRefs.isEmpty ? null : addedRefs.first;
if (wasMainImage && replacementRef != null) {
await setMainImageByHash(
data,
replacementRef,
caller: caller,
forceUpdate: forceUpdate,
);
}
await deleteImageByHash(
data,
requested,
caller: caller,
forceUpdate: forceUpdate,
);
return uploadResult ?? 'rotated image queued for sync';
} catch (e) {
return 'rotate failed: $e';
}
}