Update image loading

This commit is contained in:
Zhiyuan Zheng 2021-01-28 01:14:00 +01:00
parent ea3fa87057
commit c9c6e126ae
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
10 changed files with 72 additions and 166 deletions

View File

@ -158,6 +158,15 @@ PODS:
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (6.7.2):
- GoogleUtilities/Logger
- libwebp (1.1.0):
- libwebp/demux (= 1.1.0)
- libwebp/mux (= 1.1.0)
- libwebp/webp (= 1.1.0)
- libwebp/demux (1.1.0):
- libwebp/webp
- libwebp/mux (1.1.0):
- libwebp/demux
- libwebp/webp (1.1.0)
- nanopb (0.3.9011):
- nanopb/decode (= 0.3.9011)
- nanopb/encode (= 0.3.9011)
@ -402,6 +411,10 @@ PODS:
- React-Core
- RNCMaskedView (0.1.10):
- React
- RNFastImage (8.3.4):
- React-Core
- SDWebImage (~> 5.8)
- SDWebImageWebPCoder (~> 0.6.1)
- RNGestureHandler (1.8.0):
- React
- RNReanimated (2.0.0-rc.0):
@ -440,6 +453,12 @@ PODS:
- Sentry (= 6.0.9)
- RNSVG (12.1.0):
- React
- SDWebImage (5.10.3):
- SDWebImage/Core (= 5.10.3)
- SDWebImage/Core (5.10.3)
- SDWebImageWebPCoder (0.6.1):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.7)
- Sentry (6.0.9):
- Sentry/Core (= 6.0.9)
- Sentry/Core (6.0.9)
@ -525,6 +544,7 @@ DEPENDENCIES:
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
- RNFastImage (from `../node_modules/react-native-fast-image`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
@ -558,8 +578,11 @@ SPEC REPOS:
- GoogleDataTransport
- GoogleDataTransportCCTSupport
- GoogleUtilities
- libwebp
- nanopb
- PromisesObjC
- SDWebImage
- SDWebImageWebPCoder
- Sentry
EXTERNAL SOURCES:
@ -683,6 +706,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCMaskedView:
:path: "../node_modules/@react-native-community/masked-view"
RNFastImage:
:path: "../node_modules/react-native-fast-image"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNReanimated:
@ -768,6 +793,7 @@ SPEC CHECKSUMS:
GoogleDataTransport: 9a8a16f79feffc7f42096743de2a7c4815e84020
GoogleDataTransportCCTSupport: 0f39025e8cf51f168711bd3fb773938d7e62ddb5
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
@ -796,11 +822,14 @@ SPEC CHECKSUMS:
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
RNCAsyncStorage: da95b83e241a7f5efe3da1a949b3ec3175380be0
RNCMaskedView: 5a8ec07677aa885546a0d98da336457e2bea557f
RNFastImage: d4870d58f5936111c56218dbd7fcfc18e65b58ff
RNGestureHandler: 7a5833d0f788dbd107fbb913e09aa0c1ff333c39
RNReanimated: b9c929bfff7dedc9c89ab1875f1c6151023358d9
RNScreens: 3d682bcaba69a4f8e55543d90818704f34338db1
RNSentry: 6b46b6fc1d715a378fbaa5d7d43bc9ce99b500e5
RNSVG: ce9d996113475209013317e48b05c21ee988d42e
SDWebImage: e378178472b735e84b007bfb55514c97948a0598
SDWebImageWebPCoder: d0dac55073088d24b2ac1b191a71a8f8d0adac21
Sentry: 388c9dc093b2fd3a264466a5c5b21e25959610a9
UMAppLoader: 92d044af52626af3d81a69796ad666fc7a9a7d78
UMBarCodeScannerInterface: 3f6c1b09ef4b867ce752b8c0b3893bcf9cd85f32

View File

@ -50,13 +50,12 @@
"gl-react-expo": "^4.0.1",
"i18next": "^19.8.4",
"lodash": "^4.17.20",
"pretty-bytes": "^5.5.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-i18next": "^11.8.5",
"react-native": "~0.63.4",
"react-native-animated-spinkit": "^1.4.2",
"react-native-expo-image-cache": "^4.1.0",
"react-native-fast-image": "^8.3.4",
"react-native-feather": "^1.0.2",
"react-native-gesture-handler": "~1.8.0",
"react-native-htmlview": "^0.16.0",

View File

@ -1,80 +1,20 @@
import { StyleConstants } from '@utils/styles/constants'
import { Surface } from 'gl-react-expo'
import { Blurhash } from 'gl-react-blurhash'
import React, { useCallback, useEffect, useState } from 'react'
import React, { useCallback, useState } from 'react'
import {
Image,
ImageStyle,
Pressable,
StyleProp,
StyleSheet,
View,
ViewStyle
} from 'react-native'
import { Image as ImageCache } from 'react-native-expo-image-cache'
import FastImage from 'react-native-fast-image'
import { useTheme } from '@utils/styles/ThemeManager'
type CancelPromise = ((reason?: Error) => void) | undefined
interface ImageSizeOperation {
start: () => Promise<string>
cancel: CancelPromise
}
const getImageSize = ({
preview,
original,
remote
}: {
preview?: string
original: string
remote?: string
}): ImageSizeOperation => {
let cancel: CancelPromise
const start = (): Promise<string> =>
new Promise<string>((resolve, reject) => {
cancel = reject
Image.getSize(
preview || '',
() => {
cancel = undefined
resolve(preview!)
},
() => {
cancel = reject
Image.getSize(
original,
() => {
cancel = undefined
resolve(original)
},
() => {
cancel = reject
if (!remote) {
reject()
} else {
Image.getSize(
remote,
() => {
cancel = undefined
resolve(remote)
},
error => {
reject(error)
}
)
}
}
)
}
)
})
return { start, cancel }
}
export interface Props {
hidden?: boolean
cache?: boolean
uri: { preview?: string; original?: string; remote?: string }
uri: { preview?: string; original: string; remote?: string }
blurhash?: string
dimension?: { width: number; height: number }
onPress?: () => void
@ -84,7 +24,6 @@ export interface Props {
const GracefullyImage: React.FC<Props> = ({
hidden = false,
cache = false,
uri,
blurhash,
dimension,
@ -93,68 +32,32 @@ const GracefullyImage: React.FC<Props> = ({
imageStyle
}) => {
const { mode, theme } = useTheme()
const [imageVisible, setImageVisible] = useState<string>()
useEffect(() => {
let mounted = true
let cancel: CancelPromise
const sideEffect = async (): Promise<void> => {
try {
const prefetchImage = getImageSize(uri as { original: string })
cancel = prefetchImage.cancel
const res = await prefetchImage.start()
if (mounted) {
setImageVisible(res)
}
return
} catch (error) {
if (__DEV__) console.warn('Image', error)
}
}
if (uri.original) {
sideEffect()
}
return () => {
mounted = false
if (cancel) {
cancel()
}
}
}, [uri])
const [imageLoaded, setImageLoaded] = useState(false)
const children = useCallback(() => {
if (imageVisible && !hidden) {
if (cache) {
return (
<ImageCache uri={imageVisible} style={[styles.image, imageStyle]} />
)
} else {
return (
<Image
source={{ uri: imageVisible }}
style={[styles.image, imageStyle]}
/>
)
}
} else if (blurhash) {
return (
<Surface
style={{
width: '100%',
height: '100%',
position: 'absolute',
top: StyleConstants.Spacing.XS / 2,
left: StyleConstants.Spacing.XS / 2
}}
>
<Blurhash hash={blurhash} />
</Surface>
)
}
}, [hidden, mode, imageVisible])
return (
<>
<FastImage
source={{ uri: uri.preview || uri.original || uri.remote }}
style={[styles.image, imageStyle]}
onLoad={() => setImageLoaded(true)}
/>
{blurhash && (hidden || !imageLoaded) ? (
<Surface
style={{
width: '100%',
height: '100%',
position: 'absolute',
top: StyleConstants.Spacing.XS / 2,
left: StyleConstants.Spacing.XS / 2
}}
>
<Blurhash hash={blurhash} />
</Surface>
) : null}
</>
)
}, [hidden, imageLoaded, mode, uri])
return (
<Pressable

View File

@ -1,8 +1,8 @@
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useMemo } from 'react'
import { StyleSheet, Text, View } from 'react-native'
import { Image } from 'react-native-expo-image-cache'
import { StyleSheet, Text } from 'react-native'
import FastImage from 'react-native-fast-image'
const regexEmoji = new RegExp(/(:[A-Za-z0-9_]+:)/)
@ -53,10 +53,9 @@ const ParseEmojis: React.FC<Props> = ({
<Text key={i}>
{/* When emoji starts a paragraph, lineHeight will break */}
{i === 0 ? <Text> </Text> : null}
<Image
transitionDuration={0}
uri={emojis[emojiIndex].url}
style={[styles.image]}
<FastImage
source={{ uri: emojis[emojiIndex].url }}
style={styles.image}
/>
</Text>
)

View File

@ -32,7 +32,6 @@ const Avatars: React.FC<{ accounts: Mastodon.Account[] }> = ({ accounts }) => {
{accounts.slice(0, 4).map(account => (
<GracefullyImage
key={account.id}
cache
uri={{ original: account.avatar_static }}
dimension={{
width: StyleConstants.Avatar.M,

View File

@ -75,10 +75,11 @@ const AttachmentAudio: React.FC<Props> = ({
)
) : (
<>
{(audio.preview_url || audio.preview_remote_url) && (
{audio.preview_url && (
<GracefullyImage
uri={{
original: audio.preview_url || audio.preview_remote_url
original: audio.preview_url,
remote: audio.preview_remote_url
}}
style={styles.background}
/>

View File

@ -23,7 +23,6 @@ const TimelineAvatar: React.FC<Props> = ({ queryKey, account }) => {
return (
<GracefullyImage
cache
onPress={onPress}
uri={{ original: account.avatar_static }}
dimension={{

View File

@ -12,10 +12,8 @@ import {
getSettingsBrowser
} from '@utils/slices/settingsSlice'
import { useTheme } from '@utils/styles/ThemeManager'
import prettyBytes from 'pretty-bytes'
import React, { useEffect, useState } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { CacheManager } from 'react-native-expo-image-cache'
import { useDispatch, useSelector } from 'react-redux'
const SettingsApp: React.FC = () => {
@ -28,11 +26,6 @@ const SettingsApp: React.FC = () => {
const settingsTheme = useSelector(getSettingsTheme)
const settingsBrowser = useSelector(getSettingsBrowser)
const [cacheSize, setCacheSize] = useState<number>()
useEffect(() => {
CacheManager.getCacheSize().then(size => setCacheSize(size))
}, [])
return (
<MenuContainer>
<MenuRow
@ -155,19 +148,6 @@ const SettingsApp: React.FC = () => {
)
}
/>
<MenuRow
title={t('content.cache.heading')}
content={cacheSize ? prettyBytes(cacheSize) : t('content.cache.empty')}
iconBack='ChevronRight'
onPress={async () => {
analytics('settings_cache_press', {
size: cacheSize ? prettyBytes(cacheSize) : 'empty'
})
await CacheManager.clearCache()
haptics('Success')
setCacheSize(0)
}}
/>
</MenuContainer>
)
}

View File

@ -35,7 +35,7 @@ const AccountInformationAvatar: React.FC<Props> = ({ account, myInfo }) => {
>
<GracefullyImage
style={styles.base}
uri={{ original: account?.avatar }}
uri={{ original: account?.avatar || '' }}
dimension={dimension}
/>
</Pressable>

View File

@ -7289,7 +7289,7 @@ lodash.throttle@^4.1.1:
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
lodash@^4, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.0:
lodash@^4, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.0:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
@ -8791,13 +8791,10 @@ react-native-animated-spinkit@^1.4.2:
resolved "https://registry.yarnpkg.com/react-native-animated-spinkit/-/react-native-animated-spinkit-1.5.1.tgz#a251d3c30f6c1876896252d8d2febf03759bf457"
integrity sha512-n4zXVY2Ro3iprmznLEGmcmG/H8oXdG3AmHrXMa1lfH+gM+zL8gGTL91BGlrJC7Th9gEbB7Q2Glxt+GFW62GLQw==
react-native-expo-image-cache@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/react-native-expo-image-cache/-/react-native-expo-image-cache-4.1.0.tgz#649cbe9786249134d3eafed5baba50bbfa80c029"
integrity sha512-U6xHtuyalNZThhM11lu4+mRNSpJFkdh4dSLbWkKAj5QfY63cKlTnDVtv8c88njn71GHL4exEzf8hNKBMWhH37Q==
dependencies:
crypto-js "^3.1.9-1"
lodash "^4.17.4"
react-native-fast-image@^8.3.4:
version "8.3.4"
resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.3.4.tgz#79edca177e30311b19d59ff335625bcbe22650d7"
integrity sha512-LpzAdjUphihUpVEBn5fEv5AILe55rHav0YiZroPZ1rumKDhAl4u2cG01ku2Pb7l8sayjTsNu7FuURAlXUUDsow==
react-native-feather@^1.0.2:
version "1.0.2"