From 13efb563243f396bd39bbf9025351b36bce36ad1 Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Sun, 14 Feb 2021 00:27:21 +0100 Subject: [PATCH] Fixed #9 --- src/@types/react-navigation.d.ts | 2 + src/components/GracefullyImage.tsx | 155 ++++++------ src/components/Timeline/Shared/Attachment.tsx | 8 +- .../Timeline/Shared/Attachment/Image.tsx | 7 +- src/components/Timeline/Shared/Avatar.tsx | 12 +- src/modules/react-native-image-viewing | 2 +- src/screens/ImagesViewer.tsx | 231 +++++++++--------- 7 files changed, 214 insertions(+), 203 deletions(-) diff --git a/src/@types/react-navigation.d.ts b/src/@types/react-navigation.d.ts index 8addefc8..5bc2ba18 100644 --- a/src/@types/react-navigation.d.ts +++ b/src/@types/react-navigation.d.ts @@ -51,6 +51,8 @@ declare namespace Nav { 'Screen-ImagesViewer': { imageUrls: { url: Mastodon.AttachmentImage['url'] + width?: number + height?: number preview_url: Mastodon.AttachmentImage['preview_url'] remote_url?: Mastodon.AttachmentImage['remote_url'] imageIndex: number diff --git a/src/components/GracefullyImage.tsx b/src/components/GracefullyImage.tsx index a44b0cc9..dad2d500 100644 --- a/src/components/GracefullyImage.tsx +++ b/src/components/GracefullyImage.tsx @@ -1,12 +1,17 @@ import { StyleConstants } from '@utils/styles/constants' -import React, { useCallback, useMemo, useState } from 'react' +import { useTheme } from '@utils/styles/ThemeManager' +import React, { useCallback, useMemo, useRef, useState } from 'react' import { Pressable, StyleProp, StyleSheet, ViewStyle } from 'react-native' import { Blurhash } from 'react-native-blurhash' import FastImage, { ImageStyle } from 'react-native-fast-image' -import { useTheme } from '@utils/styles/ThemeManager' + +// blurhas -> if blurhash, show before any loading succeed +// original -> load original +// original, remote -> if original failed, then remote +// preview, original -> first show preview, then original +// preview, original, remote -> first show preview, then original, if original failed, then remote export interface Props { - sharedElement?: string hidden?: boolean uri: { preview?: string; original: string; remote?: string } blurhash?: string @@ -14,115 +19,113 @@ export interface Props { onPress?: () => void style?: StyleProp imageStyle?: StyleProp + // For image viewer when there is no image size available + setImageDimensions?: React.Dispatch< + React.SetStateAction<{ + width: number + height: number + }> + > } const GracefullyImage = React.memo( ({ - sharedElement, hidden = false, uri, blurhash, dimension, onPress, style, - imageStyle + imageStyle, + setImageDimensions }: Props) => { - const { mode, theme } = useTheme() - const [previewLoaded, setPreviewLoaded] = useState( - uri.preview ? false : true + const { theme } = useTheme() + const originalFailed = useRef(false) + const [imageLoaded, setImageLoaded] = useState(false) + + const source = useMemo(() => { + if (originalFailed.current) { + return { uri: uri.remote || undefined } + } else { + return { uri: uri.original } + } + }, [originalFailed.current]) + const onLoad = useCallback( + ({ nativeEvent }) => { + setImageLoaded(true) + setImageDimensions && + setImageDimensions({ + width: nativeEvent.width, + height: nativeEvent.height + }) + }, + [source.uri] ) - const [originalLoaded, setOriginalLoaded] = useState(false) - const [originalFailed, setOriginalFailed] = useState(false) - const [remoteLoaded, setRemoteLoaded] = useState(uri.remote ? false : true) - - const sourceUri = useMemo(() => { - if (previewLoaded) { - if (originalFailed) { - return uri.remote - } else { - return uri.original - } - } else { - return uri.preview - } - }, [previewLoaded, originalLoaded, originalFailed, remoteLoaded]) - const onLoad = useCallback(() => { - if (previewLoaded) { - if (originalFailed) { - return setRemoteLoaded(true) - } else { - return setOriginalLoaded(true) - } - } else { - return setPreviewLoaded(true) - } - }, [previewLoaded, originalLoaded, originalFailed, remoteLoaded]) const onError = useCallback(() => { - if (previewLoaded) { - if (originalFailed) { - return - } else { - return setOriginalFailed(true) - } - } else { - return + if (!originalFailed.current) { + originalFailed.current = true } - }, [previewLoaded, originalLoaded, originalFailed, remoteLoaded]) + }, [originalFailed.current]) - const children = useCallback(() => { - return ( - <> + const previewView = useMemo( + () => + uri.preview && !imageLoaded ? ( - {blurhash && - (hidden || !(previewLoaded || originalLoaded || remoteLoaded)) ? ( - - ) : null} - - ) - }, [hidden, previewLoaded, originalLoaded, remoteLoaded, mode, uri]) + ) : null, + [imageLoaded] + ) + const originalView = useMemo( + () => ( + + ), + [source, imageLoaded] + ) + const blurhashView = useMemo(() => { + return blurhash && (hidden || !imageLoaded) ? ( + + ) : null + }, [hidden, imageLoaded]) return ( ) }, (prev, next) => { let skipUpdate = true skipUpdate = prev.hidden === next.hidden + skipUpdate = prev.uri.preview === next.uri.preview skipUpdate = prev.uri.original === next.uri.original + skipUpdate = prev.uri.remote === next.uri.remote return false } ) const styles = StyleSheet.create({ - image: { - flex: 1 + blurhash: { + width: '100%', + height: '100%', + position: 'absolute', + top: StyleConstants.Spacing.XS / 2, + left: StyleConstants.Spacing.XS / 2 } }) diff --git a/src/components/Timeline/Shared/Attachment.tsx b/src/components/Timeline/Shared/Attachment.tsx index bb3e3b76..3eb123f5 100644 --- a/src/components/Timeline/Shared/Attachment.tsx +++ b/src/components/Timeline/Shared/Attachment.tsx @@ -32,11 +32,7 @@ const TimelineAttachment: React.FC = ({ status }) => { haptics('Light') }, []) - let imageUrls: (App.IImageInfo & { - preview_url: Mastodon.AttachmentImage['preview_url'] - remote_url?: Mastodon.AttachmentImage['remote_url'] - imageIndex: number - })[] = [] + let imageUrls: Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls'] = [] const navigation = useNavigation() const navigateToImagesViewer = (imageIndex: number) => navigation.navigate('Screen-ImagesViewer', { @@ -52,6 +48,8 @@ const TimelineAttachment: React.FC = ({ status }) => { url: attachment.url, preview_url: attachment.preview_url, remote_url: attachment.remote_url, + width: attachment.meta?.original?.width, + height: attachment.meta?.original?.height, imageIndex: index }) return ( diff --git a/src/components/Timeline/Shared/Attachment/Image.tsx b/src/components/Timeline/Shared/Attachment/Image.tsx index ba4739d1..9c2dddaa 100644 --- a/src/components/Timeline/Shared/Attachment/Image.tsx +++ b/src/components/Timeline/Shared/Attachment/Image.tsx @@ -28,12 +28,7 @@ const AttachmentImage: React.FC = ({ return (