Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/libs/actions/Attachment/index.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ async function getCachedAttachment({attachmentID, attachment, currentSource}: Ge
// exists. If it was purged, fall back to the current source and re-cache it.
const localFileExists = await RNFS.exists(localSource);
if (localFileExists) {
return localSource;
// The path is stored without a scheme so RNFS file operations (exists/unlink) accept it, but
// React Native's <Image> on Android only loads a local file when it carries a `file://`
// scheme (a bare path renders as a broken thumbnail), so add the scheme before the path
// reaches the image renderer.
return localSource.startsWith('file://') ? localSource : `file://${localSource}`;
}
cacheAttachment({attachmentID, uri: currentSource});
}
Expand Down
14 changes: 14 additions & 0 deletions tests/actions/AttachmentTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,20 @@ describe('AttachmentStorage', () => {
// Then the dead local path is not returned
expect(resolvedSource).toBe(sourceURL);
});
it('should return the cached local source with a file:// scheme so the native Image can load it', async () => {
// Given a cached attachment whose stored file path (no scheme) still exists on disk
const attachmentID = 'cached-attachment';
const sourceURL = 'https://images.unsplash.com/photo-1726066012751-2adfb5485977?w=500';
const localSource = `/mock/caches/attachments/${attachmentID}.jpg`;
const attachment = {attachmentID, source: localSource, remoteSource: sourceURL};
mockRNFS.exists.mockResolvedValueOnce(true);

// When reading it from the cache
const resolvedSource = await getCachedAttachment({attachmentID, attachment, currentSource: sourceURL});

// Then the path is returned prefixed with file:// (Android's <Image> can't load a local path without a scheme)
expect(resolvedSource).toBe(`file://${localSource}`);
});
it('should cache markdown attachment', async () => {
// Given the attachment data consisting of sourceURL and markdown comment text
const sourceURL = 'https://images.unsplash.com/photo-1726066012751-2adfb5485977?w=500';
Expand Down
Loading