diff --git a/assets/images/gallery-not-found.svg b/assets/images/gallery-not-found.svg new file mode 100644 index 000000000000..25da973ce9cb --- /dev/null +++ b/assets/images/gallery-not-found.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/AttachmentOfflineIndicator.tsx b/src/components/AttachmentOfflineIndicator.tsx index d425e6f18e0e..4ff1940ba004 100644 --- a/src/components/AttachmentOfflineIndicator.tsx +++ b/src/components/AttachmentOfflineIndicator.tsx @@ -37,7 +37,7 @@ function AttachmentOfflineIndicator({isPreview = false}: AttachmentOfflineIndica return ( setHasLoadFailed(true)} + onMeasure={() => setHasLoadFailed(false)} + fallbackIconBackground={theme.highlightBG} + fallbackIconColor={theme.border} /> ); @@ -102,6 +110,7 @@ function ImageRenderer({tnode}: ImageRendererProps) { shouldUseHapticsOnLongPress accessibilityRole={CONST.ROLE.BUTTON} accessibilityLabel={translate('accessibilityHints.viewAttachment')} + disabled={hasLoadFailed} > {thumbnailImageComponent} diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index cd9c97105ff0..90f0e0d8a151 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -93,6 +93,7 @@ import FlagLevelTwo from '@assets/images/flag_level_02.svg'; import FlagLevelThree from '@assets/images/flag_level_03.svg'; import Folder from '@assets/images/folder.svg'; import Fullscreen from '@assets/images/fullscreen.svg'; +import GalleryNotFound from '@assets/images/gallery-not-found.svg'; import Gallery from '@assets/images/gallery.svg'; import Gear from '@assets/images/gear.svg'; import Globe from '@assets/images/globe.svg'; @@ -404,4 +405,5 @@ export { Bookmark, Star, QBDSquare, + GalleryNotFound, }; diff --git a/src/components/ThumbnailImage.tsx b/src/components/ThumbnailImage.tsx index cea528e4537c..f283058042eb 100644 --- a/src/components/ThumbnailImage.tsx +++ b/src/components/ThumbnailImage.tsx @@ -55,6 +55,12 @@ type ThumbnailImageProps = { /** The object position of image */ objectPosition?: ImageObjectPosition; + + /** Callback fired when the image fails to load */ + onLoadFailure?: () => void; + + /** Callback fired when the image has been measured */ + onMeasure?: () => void; }; type UpdateImageSizeParams = { @@ -75,6 +81,8 @@ function ThumbnailImage({ fallbackIconColor, fallbackIconBackground, objectPosition = CONST.IMAGE_OBJECT_POSITION.INITIAL, + onLoadFailure, + onMeasure, }: ThumbnailImageProps) { const styles = useThemeStyles(); const theme = useTheme(); @@ -137,8 +145,14 @@ function ThumbnailImage({ setFailedToLoad(true)} + onMeasure={(args) => { + updateImageSize(args); + onMeasure?.(); + }} + onLoadFailure={() => { + setFailedToLoad(true); + onLoadFailure?.(); + }} isAuthTokenRequired={isAuthTokenRequired} objectPosition={objectPosition} />