getImageByHash method
gets image specified by its hash
Implementation
Future<ImageData?> getImageByHash(String hash, {Data? owner}) async {
// Scoped/local hashes (with folders or local prefix) must not trigger remote fetches
final isLocalScoped = hash.contains('/') ||
hash.startsWith(LOCALLY_ADDED_PREFIX) ||
isTimestampImageFilename(hash);
// Always prefer local cache first; if present, never hit network.
try {
return await local.getImageByHash(hash, owner: owner);
} catch (_) {
// not cached locally (or unreadable) -> continue
}
// For local-scoped names we never download remotely.
if (isLocalScoped) return null;
final activeDownload = DownloadProgress.instance.active;
if (activeDownload != null &&
activeDownload.notifier.value.stepIndex <
InspectionDownloadSteps.photos) {
return null;
}
// Deduplicate in-flight downloads for the same hash to prevent repeated
// downloads on rebuild/opening views.
final key = hash;
final existing = _inflightImageFetches[key];
if (existing != null) return await existing;
Future<ImageData?> fetchRemote() async {
final progressSession = DownloadProgress.instance.active;
final progressToken = progressSession?.beginTask(
'',
key: '/image/get|$hash',
step: InspectionDownloadSteps.photos,
);
void completeProgress(bool success) {
if (progressToken != null) {
progressSession?.endTask(progressToken, success: success);
}
}
try {
await tryNetwork(requestType: Helper.SimulatedRequestType.GET);
final rap = remote.getImageByHash(hash, owner: owner);
final res = await remote.postJSON(rap.rd);
if (res == null) {
completeProgress(false);
return null;
}
final parsed = await rap.parser(res);
completeProgress(parsed != null);
if (parsed != null) return parsed;
} catch (_) {}
// last-chance local read (in case another concurrent fetch stored it)
try {
final cached = await local.getImageByHash(hash, owner: owner);
completeProgress(cached != null);
return cached;
} catch (_) {
completeProgress(false);
return null;
}
}
Future<ImageData?> fetch() async {
final session = DownloadProgress.instance.active;
if (session == null) return fetchRemote();
return session.enqueueDownload(fetchRemote);
}
final future = fetch();
_inflightImageFetches[key] = future;
try {
return await future;
} finally {
_inflightImageFetches.remove(key);
}
}