mirror of
https://github.com/tooot-app/app
synced 2025-02-15 11:20:48 +01:00
Update image loading
This commit is contained in:
parent
ea3fa87057
commit
c9c6e126ae
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
)
|
||||
|
@ -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,
|
||||
|
@ -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}
|
||||
/>
|
||||
|
@ -23,7 +23,6 @@ const TimelineAvatar: React.FC<Props> = ({ queryKey, account }) => {
|
||||
|
||||
return (
|
||||
<GracefullyImage
|
||||
cache
|
||||
onPress={onPress}
|
||||
uri={{ original: account.avatar_static }}
|
||||
dimension={{
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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>
|
||||
|
13
yarn.lock
13
yarn.lock
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user