Image performance improvements (#126)

* Switch out most images for FastImage

* Add image loading placeholders

* Fix tests
This commit is contained in:
Paul Frazee
2023-01-31 17:01:02 -06:00
committed by GitHub
parent 0ce4f57e0b
commit 5ccdec1e4f
17 changed files with 182 additions and 186 deletions
@@ -36,16 +36,14 @@ describe('SelectedPhoto', () => {
const selectedPhotoImage = await findByTestId('selectedPhotoImage')
expect(selectedPhotoImage).toBeTruthy()
// @ts-expect-error
expect(selectedPhotoImage).toHaveStyle({width: 250})
})
it('has 2 photos to render', async () => {
const {findAllByTestId} = render(<SelectedPhoto {...mockedProps} />)
const selectedPhotoImage = await findAllByTestId('selectedPhotoImage')
expect(selectedPhotoImage[0]).toBeTruthy()
// @ts-expect-error
expect(selectedPhotoImage[0]).toHaveStyle({width: 175})
expect(selectedPhotoImage[1]).toBeTruthy()
expect(selectedPhotoImage[2]).toBeFalsy()
})
it('has 3 photos to render', async () => {
@@ -57,8 +55,10 @@ describe('SelectedPhoto', () => {
)
const selectedPhotoImage = await findAllByTestId('selectedPhotoImage')
expect(selectedPhotoImage[0]).toBeTruthy()
// @ts-expect-error
expect(selectedPhotoImage[0]).toHaveStyle({width: 85})
expect(selectedPhotoImage[0]).toBeTruthy()
expect(selectedPhotoImage[1]).toBeTruthy()
expect(selectedPhotoImage[2]).toBeTruthy()
expect(selectedPhotoImage[3]).toBeFalsy()
})
it('removes a photo', async () => {
+29
View File
@@ -17,6 +17,15 @@ PODS:
- hermes-engine/Pre-built (= 0.71.0)
- hermes-engine/Pre-built (0.71.0)
- libevent (2.1.12)
- libwebp (1.2.4):
- libwebp/demux (= 1.2.4)
- libwebp/mux (= 1.2.4)
- libwebp/webp (= 1.2.4)
- libwebp/demux (1.2.4):
- libwebp/webp
- libwebp/mux (1.2.4):
- libwebp/demux
- libwebp/webp (1.2.4)
- RCT-Folly (2021.07.22.00):
- boost
- DoubleConversion
@@ -346,6 +355,10 @@ PODS:
- React-Core
- RNCClipboard (1.11.1):
- React-Core
- RNFastImage (8.6.3):
- React-Core
- SDWebImage (~> 5.11.1)
- SDWebImageWebPCoder (~> 0.8.4)
- RNFS (2.20.0):
- React-Core
- RNGestureHandler (2.8.0):
@@ -400,6 +413,12 @@ PODS:
- React-RCTImage
- RNSVG (12.5.0):
- React-Core
- SDWebImage (5.11.1):
- SDWebImage/Core (= 5.11.1)
- SDWebImage/Core (5.11.1)
- SDWebImageWebPCoder (0.8.5):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.10)
- segment-analytics-react-native (2.10.1):
- React-Core
- sovran-react-native
@@ -458,6 +477,7 @@ DEPENDENCIES:
- RNBackgroundFetch (from `../node_modules/react-native-background-fetch`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- RNFastImage (from `../node_modules/react-native-fast-image`)
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
@@ -475,6 +495,9 @@ SPEC REPOS:
trunk:
- fmt
- libevent
- libwebp
- SDWebImage
- SDWebImageWebPCoder
- Swime
- TOCropViewController
@@ -571,6 +594,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCClipboard:
:path: "../node_modules/@react-native-clipboard/clipboard"
RNFastImage:
:path: "../node_modules/react-native-fast-image"
RNFS:
:path: "../node_modules/react-native-fs"
RNGestureHandler:
@@ -606,6 +631,7 @@ SPEC CHECKSUMS:
glog: 476ee3e89abb49e07f822b48323c51c57124b572
hermes-engine: f6e715aa6c8bd38de6c13bc85e07b0a337edaa89
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
RCTRequired: fd4d923b964658aa0c4091a32c8b2004c6d9e3a6
RCTTypeSafety: c276d85975bde3d8448907235c70bf0da257adfd
@@ -645,6 +671,7 @@ SPEC CHECKSUMS:
RNBackgroundFetch: 8e16176ff415daac743a6eb57afc8e9e14dbe623
RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60
RNCClipboard: 2834e1c4af68697089cdd455ee4a4cdd198fa7dd
RNFastImage: 5c9c9fed9c076e521b3f509fe79e790418a544e8
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 62232ba8f562f7dea5ba1b3383494eb5bf97a4d3
RNImageCropPicker: 648356d68fbf9911a1016b3e3723885d28373eda
@@ -654,6 +681,8 @@ SPEC CHECKSUMS:
RNReanimated: d8d9d3d3801bda5e35e85cdffc871577d044dc2e
RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d
RNSVG: 6adc5c52d2488a476248413064b7f2832e639057
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
segment-analytics-react-native: cb097e393c3560a0d4cfd877044293e37b0050d9
sovran-react-native: fd3dc8f1a4b14acdc4ad25fc6b4ac4f52a2a2a15
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
+1
View File
@@ -48,6 +48,7 @@
"react-native": "0.71.1",
"react-native-appstate-hook": "^1.0.6",
"react-native-background-fetch": "^4.1.8",
"react-native-fast-image": "^8.6.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "^2.5.0",
"react-native-haptic-feedback": "^1.14.0",
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

+3 -6
View File
@@ -8,7 +8,7 @@ import {
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {BlurView} from '@react-native-community/blur'
import LinearGradient from 'react-native-linear-gradient'
import {AutoSizedImage} from '../util/images/AutoSizedImage'
import {Image} from '../util/images/Image'
import {Text} from '../util/text/Text'
import {s, gradients} from '../../lib/styles'
import {usePalette} from '../../lib/hooks/usePalette'
@@ -38,10 +38,7 @@ export const ExternalEmbed = ({
<ActivityIndicator size="large" style={styles.spinner} />
</View>
) : link.localThumb ? (
<AutoSizedImage
uri={link.localThumb.path}
containerStyle={styles.image}
/>
<Image uri={link.localThumb.path} style={styles.image} />
) : (
<LinearGradient
colors={[gradients.blueDark.start, gradients.blueDark.end]}
@@ -98,7 +95,7 @@ const styles = StyleSheet.create({
borderTopLeftRadius: 6,
borderTopRightRadius: 6,
width: '100%',
height: 200,
maxHeight: 200,
},
imageFallback: {
height: 160,
+3 -2
View File
@@ -1,6 +1,7 @@
import React, {useCallback} from 'react'
import {Image, StyleSheet, TouchableOpacity, View} from 'react-native'
import {StyleSheet, TouchableOpacity, View} from 'react-native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import FastImage from 'react-native-fast-image'
import {colors} from '../../lib/styles'
export const SelectedPhoto = ({
@@ -42,7 +43,7 @@ export const SelectedPhoto = ({
/>
</TouchableOpacity>
<Image
<FastImage
testID="selectedPhotoImage"
style={[styles.image, imageStyle]}
source={{uri: item}}
+14 -7
View File
@@ -1,10 +1,16 @@
import React from 'react'
import {StyleSheet, StyleProp, View, ViewStyle, Image} from 'react-native'
import {
StyleSheet,
StyleProp,
View,
ViewStyle,
Image as RNImage,
} from 'react-native'
import {AppBskyEmbedImages, AppBskyEmbedExternal} from '@atproto/api'
import LinearGradient from 'react-native-linear-gradient'
import {Link} from '../util/Link'
import {Text} from './text/Text'
import {AutoSizedImage} from './images/AutoSizedImage'
import {Image} from './images/Image'
import {ImageLayoutGrid} from './images/ImageLayoutGrid'
import {ImagesLightbox} from '../../../state/models/shell-ui'
import {useStores} from '../../../state'
@@ -37,11 +43,11 @@ export function PostEmbeds({
}
const onPressIn = (index: number) => {
const firstImageToShow = uris[index]
Image.prefetch(firstImageToShow)
RNImage.prefetch(firstImageToShow)
uris.forEach(uri => {
if (firstImageToShow !== uri) {
// First image already prefeched above
Image.prefetch(uri)
RNImage.prefetch(uri)
}
})
}
@@ -85,12 +91,12 @@ export function PostEmbeds({
} else {
return (
<View style={[styles.imagesContainer, style]}>
<AutoSizedImage
<Image
uri={embed.images[0].thumb}
onPress={() => openLightbox(0)}
onLongPress={() => onLongPress(0)}
onPressIn={() => onPressIn(0)}
containerStyle={styles.singleImage}
style={styles.singleImage}
/>
</View>
)
@@ -105,7 +111,7 @@ export function PostEmbeds({
href={link.uri}
noFeedback>
{link.thumb ? (
<AutoSizedImage uri={link.thumb} containerStyle={styles.extImage} />
<Image uri={link.thumb} style={styles.extImage} />
) : (
<LinearGradient
colors={[gradients.blueDark.start, gradients.blueDark.end]}
@@ -145,6 +151,7 @@ const styles = StyleSheet.create({
},
singleImage: {
borderRadius: 8,
maxHeight: 500,
},
extOuter: {
borderWidth: 1,
+9 -5
View File
@@ -1,7 +1,8 @@
import React from 'react'
import {Image, StyleSheet, View} from 'react-native'
import {StyleSheet, View} from 'react-native'
import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import FastImage from 'react-native-fast-image'
import {
openCamera,
openCropper,
@@ -102,13 +103,16 @@ export function UserAvatar({
bottomOffset={-10}
menuWidth={170}>
{avatar ? (
<Image
<FastImage
style={{
width: size,
height: size,
borderRadius: Math.floor(size / 2),
}}
source={{uri: avatar}}
source={{
uri: avatar,
priority: FastImage.priority.high,
}}
/>
) : (
renderSvg(size, initials)
@@ -122,10 +126,10 @@ export function UserAvatar({
</View>
</DropdownButton>
) : avatar ? (
<Image
<FastImage
style={{width: size, height: size, borderRadius: Math.floor(size / 2)}}
resizeMode="stretch"
source={{uri: avatar}}
source={{uri: avatar, priority: FastImage.priority.high}}
/>
) : (
renderSvg(size, initials)
+4 -3
View File
@@ -1,8 +1,9 @@
import React from 'react'
import {StyleSheet, View, Image} from 'react-native'
import {StyleSheet, View} from 'react-native'
import Svg, {Rect, Defs, LinearGradient, Stop} from 'react-native-svg'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {Image as PickedImage} from 'react-native-image-crop-picker'
import FastImage from 'react-native-fast-image'
import {colors, gradients} from '../../lib/styles'
import {
openCamera,
@@ -95,7 +96,7 @@ export function UserBanner({
bottomOffset={-10}
menuWidth={170}>
{banner ? (
<Image style={styles.bannerImage} source={{uri: banner}} />
<FastImage style={styles.bannerImage} source={{uri: banner}} />
) : (
renderSvg()
)}
@@ -108,7 +109,7 @@ export function UserBanner({
</View>
</DropdownButton>
) : banner ? (
<Image
<FastImage
style={styles.bannerImage}
resizeMode="cover"
source={{uri: banner}}
-126
View File
@@ -1,126 +0,0 @@
import React, {useState, useEffect} from 'react'
import {
Image,
ImageStyle,
LayoutChangeEvent,
StyleProp,
StyleSheet,
TouchableOpacity,
View,
ViewStyle,
} from 'react-native'
import {Text} from '../text/Text'
import {useTheme} from '../../../lib/ThemeContext'
import {usePalette} from '../../../lib/hooks/usePalette'
import {DELAY_PRESS_IN} from './constants'
const MAX_HEIGHT = 300
interface Dim {
width: number
height: number
}
export function AutoSizedImage({
uri,
onPress,
onLongPress,
onPressIn,
style,
containerStyle,
}: {
uri: string
onPress?: () => void
style?: StyleProp<ImageStyle>
containerStyle?: StyleProp<ViewStyle>
}) {
const theme = useTheme()
const errPal = usePalette('error')
const [error, setError] = useState<string | undefined>('')
const [imgInfo, setImgInfo] = useState<Dim | undefined>()
const [containerInfo, setContainerInfo] = useState<Dim | undefined>()
useEffect(() => {
let aborted = false
if (!imgInfo) {
Image.getSize(
uri,
(width: number, height: number) => {
if (!aborted) {
setImgInfo({width, height})
}
},
(err: any) => {
if (!aborted) {
setError(String(err))
}
},
)
}
return () => {
aborted = true
}
}, [uri, imgInfo])
const onLayout = (evt: LayoutChangeEvent) => {
setContainerInfo({
width: evt.nativeEvent.layout.width,
height: evt.nativeEvent.layout.height,
})
}
let calculatedStyle: StyleProp<ViewStyle> | undefined
if (imgInfo && containerInfo) {
// imgInfo.height / imgInfo.width = x / containerInfo.width
// x = imgInfo.height / imgInfo.width * containerInfo.width
calculatedStyle = {
height: Math.min(
MAX_HEIGHT,
(imgInfo.height / imgInfo.width) * containerInfo.width,
),
}
}
return (
<View style={style}>
<TouchableOpacity
onPress={onPress}
onLongPress={onLongPress}
onPressIn={onPressIn}
delayPressIn={DELAY_PRESS_IN}>
{error ? (
<View style={[styles.errorContainer, errPal.view, containerStyle]}>
<Text style={errPal.text}>{error}</Text>
</View>
) : calculatedStyle ? (
<View style={[styles.container, containerStyle]}>
<Image style={calculatedStyle} source={{uri}} />
</View>
) : (
<View
style={[
style,
styles.placeholder,
{backgroundColor: theme.palette.default.backgroundLight},
]}
onLayout={onLayout}
/>
)}
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
placeholder: {
width: '100%',
aspectRatio: 1,
},
errorContainer: {
paddingHorizontal: 12,
paddingVertical: 8,
},
container: {
overflow: 'hidden',
},
})
+40
View File
@@ -0,0 +1,40 @@
import React from 'react'
import {StyleProp, StyleSheet, TouchableOpacity, ViewStyle} from 'react-native'
import FastImage from 'react-native-fast-image'
import {DELAY_PRESS_IN} from './constants'
import {LOADING} from '../../../lib/assets'
export function Image({
uri,
onPress,
onLongPress,
onPressIn,
style,
}: {
uri: string
onPress?: () => void
onLongPress?: () => void
onPressIn?: () => void
style?: StyleProp<ViewStyle>
}) {
return (
<TouchableOpacity
onPress={onPress}
onLongPress={onLongPress}
onPressIn={onPressIn}
delayPressIn={DELAY_PRESS_IN}
style={[styles.container, style]}>
<FastImage style={styles.image} source={{uri}} defaultSource={LOADING} />
</TouchableOpacity>
)
}
const styles = StyleSheet.create({
container: {
overflow: 'hidden',
},
image: {
width: '100%',
aspectRatio: 1,
},
})
+2 -2
View File
@@ -1,12 +1,12 @@
import React from 'react'
import {
Image,
StyleProp,
StyleSheet,
TouchableWithoutFeedback,
View,
ViewStyle,
} from 'react-native'
import FastImage from 'react-native-fast-image'
export function ImageHorzList({
uris,
@@ -21,7 +21,7 @@ export function ImageHorzList({
<View style={[styles.flexRow, style]}>
{uris.map((uri, i) => (
<TouchableWithoutFeedback key={i} onPress={() => onPress?.(i)}>
<Image source={{uri}} style={styles.image} />
<FastImage source={{uri}} style={styles.image} />
</TouchableWithoutFeedback>
))}
</View>
+49 -13
View File
@@ -1,7 +1,5 @@
import React from 'react'
import {
Image,
ImageStyle,
LayoutChangeEvent,
StyleProp,
StyleSheet,
@@ -9,6 +7,8 @@ import {
View,
ViewStyle,
} from 'react-native'
import FastImage, {ImageStyle as FastImageStyle} from 'react-native-fast-image'
import {LOADING} from '../../../lib/assets'
import {DELAY_PRESS_IN} from './constants'
interface Dim {
@@ -73,7 +73,7 @@ function ImageLayoutGridInner({
onPressIn?: (index: number) => void
containerInfo: Dim
}) {
const size1 = React.useMemo<ImageStyle>(() => {
const size1 = React.useMemo<StyleProp<FastImageStyle>>(() => {
if (type === 'three') {
const size = (containerInfo.width - 10) / 3
return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
@@ -82,7 +82,7 @@ function ImageLayoutGridInner({
return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
}
}, [type, containerInfo])
const size2 = React.useMemo<ImageStyle>(() => {
const size2 = React.useMemo<StyleProp<FastImageStyle>>(() => {
if (type === 'three') {
const size = ((containerInfo.width - 10) / 3) * 2 + 5
return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
@@ -100,7 +100,11 @@ function ImageLayoutGridInner({
onPress={() => onPress?.(0)}
onPressIn={() => onPressIn?.(0)}
onLongPress={() => onLongPress(0)}>
<Image source={{uri: uris[0]}} style={size1} />
<FastImage
source={{uri: uris[0]}}
style={size1}
defaultSource={LOADING}
/>
</TouchableOpacity>
<View style={styles.wSpace} />
<TouchableOpacity
@@ -108,7 +112,11 @@ function ImageLayoutGridInner({
onPress={() => onPress?.(1)}
onPressIn={() => onPressIn?.(1)}
onLongPress={() => onLongPress(1)}>
<Image source={{uri: uris[1]}} style={size1} />
<FastImage
source={{uri: uris[1]}}
style={size1}
defaultSource={LOADING}
/>
</TouchableOpacity>
</View>
)
@@ -121,7 +129,11 @@ function ImageLayoutGridInner({
onPress={() => onPress?.(0)}
onPressIn={() => onPressIn?.(0)}
onLongPress={() => onLongPress(0)}>
<Image source={{uri: uris[0]}} style={size2} />
<FastImage
source={{uri: uris[0]}}
style={size2}
defaultSource={LOADING}
/>
</TouchableOpacity>
<View style={styles.wSpace} />
<View>
@@ -130,7 +142,11 @@ function ImageLayoutGridInner({
onPress={() => onPress?.(1)}
onPressIn={() => onPressIn?.(1)}
onLongPress={() => onLongPress(1)}>
<Image source={{uri: uris[1]}} style={size1} />
<FastImage
source={{uri: uris[1]}}
style={size1}
defaultSource={LOADING}
/>
</TouchableOpacity>
<View style={styles.hSpace} />
<TouchableOpacity
@@ -138,7 +154,11 @@ function ImageLayoutGridInner({
onPress={() => onPress?.(2)}
onPressIn={() => onPressIn?.(2)}
onLongPress={() => onLongPress(2)}>
<Image source={{uri: uris[2]}} style={size1} />
<FastImage
source={{uri: uris[2]}}
style={size1}
defaultSource={LOADING}
/>
</TouchableOpacity>
</View>
</View>
@@ -153,7 +173,11 @@ function ImageLayoutGridInner({
onPress={() => onPress?.(0)}
onPressIn={() => onPressIn?.(0)}
onLongPress={() => onLongPress(0)}>
<Image source={{uri: uris[0]}} style={size1} />
<FastImage
source={{uri: uris[0]}}
style={size1}
defaultSource={LOADING}
/>
</TouchableOpacity>
<View style={styles.hSpace} />
<TouchableOpacity
@@ -161,7 +185,11 @@ function ImageLayoutGridInner({
onPress={() => onPress?.(2)}
onPressIn={() => onPressIn?.(2)}
onLongPress={() => onLongPress(2)}>
<Image source={{uri: uris[2]}} style={size1} />
<FastImage
source={{uri: uris[2]}}
style={size1}
defaultSource={LOADING}
/>
</TouchableOpacity>
</View>
<View style={styles.wSpace} />
@@ -171,7 +199,11 @@ function ImageLayoutGridInner({
onPress={() => onPress?.(1)}
onPressIn={() => onPressIn?.(1)}
onLongPress={() => onLongPress(1)}>
<Image source={{uri: uris[1]}} style={size1} />
<FastImage
source={{uri: uris[1]}}
style={size1}
defaultSource={LOADING}
/>
</TouchableOpacity>
<View style={styles.hSpace} />
<TouchableOpacity
@@ -179,7 +211,11 @@ function ImageLayoutGridInner({
onPress={() => onPress?.(3)}
onPressIn={() => onPressIn?.(3)}
onLongPress={() => onLongPress(3)}>
<Image source={{uri: uris[3]}} style={size1} />
<FastImage
source={{uri: uris[3]}}
style={size1}
defaultSource={LOADING}
/>
</TouchableOpacity>
</View>
</View>
+5 -4
View File
@@ -1,5 +1,6 @@
import {ImageSourcePropType} from 'react-native'
import {ImageRequireSource} from 'react-native'
export const DEF_AVATAR: ImageSourcePropType = require('../../../public/img/default-avatar.jpg')
export const TABS_EXPLAINER: ImageSourcePropType = require('../../../public/img/tabs-explainer.jpg')
export const CLOUD_SPLASH: ImageSourcePropType = require('../../../public/img/cloud-splash.png')
export const DEF_AVATAR: ImageRequireSource = require('../../../public/img/default-avatar.jpg')
export const TABS_EXPLAINER: ImageRequireSource = require('../../../public/img/tabs-explainer.jpg')
export const CLOUD_SPLASH: ImageRequireSource = require('../../../public/img/cloud-splash.png')
export const LOADING: ImageRequireSource = require('../../../public/img/loading.png')
+9 -4
View File
@@ -1,7 +1,12 @@
import {ImageSourcePropType} from 'react-native'
import {ImageRequireSource} from 'react-native'
export const DEF_AVATAR: ImageSourcePropType = {uri: '/img/default-avatar.jpg'}
export const TABS_EXPLAINER: ImageSourcePropType = {
// @ts-ignore we need to pretend -prf
export const DEF_AVATAR: ImageRequireSource = {uri: '/img/default-avatar.jpg'}
// @ts-ignore we need to pretend -prf
export const TABS_EXPLAINER: ImageRequireSource = {
uri: '/img/tabs-explainer.jpg',
}
export const CLOUD_SPLASH: ImageSourcePropType = {uri: '/img/cloud-splash.png'}
// @ts-ignore we need to pretend -prf
export const CLOUD_SPLASH: ImageRequireSource = {uri: '/img/cloud-splash.png'}
// @ts-ignore we need to pretend -prf
export const LOADING: ImageRequireSource = {uri: '/img/loading.png'}
+3 -8
View File
@@ -1,11 +1,6 @@
import React, {useState} from 'react'
import {
Image,
SafeAreaView,
StyleSheet,
TouchableOpacity,
View,
} from 'react-native'
import {SafeAreaView, StyleSheet, TouchableOpacity, View} from 'react-native'
import FastImage, {Source as FISource} from 'react-native-fast-image'
import {observer} from 'mobx-react-lite'
import {Signin} from '../com/login/Signin'
import {CreateAccount} from '../com/login/CreateAccount'
@@ -64,7 +59,7 @@ export const Login = observer(() => {
if (screenState === ScreenState.S_SigninOrCreateAccount) {
return (
<View style={styles.container}>
<Image source={CLOUD_SPLASH} style={styles.bgImg} />
<FastImage source={CLOUD_SPLASH as FISource} style={styles.bgImg} />
<SafeAreaView testID="noSessionView" style={styles.container}>
<ErrorBoundary>
<SigninOrCreateAccount
+5
View File
@@ -11076,6 +11076,11 @@ react-native-dotenv@^3.3.1:
dependencies:
dotenv "^16.0.3"
react-native-fast-image@^8.6.3:
version "8.6.3"
resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.6.3.tgz#6edc3f9190092a909d636d93eecbcc54a8822255"
integrity sha512-Sdw4ESidXCXOmQ9EcYguNY2swyoWmx53kym2zRsvi+VeFCHEdkO+WG1DK+6W81juot40bbfLNhkc63QnWtesNg==
react-native-fs@^2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/react-native-fs/-/react-native-fs-2.20.0.tgz#05a9362b473bfc0910772c0acbb73a78dbc810f6"