fix: images cropping on different devices (#524)

* feat: add image sizes using Image.getSizeWithHeaders

* chore: 🤖 bild i fakeData

* add rounded corners to embedded images in content

* add debug information

* add more debug info

Co-authored-by: Kajetan Kazimierczak <kajetan@hotmail.com>
This commit is contained in:
Jonathan Edenström 2021-11-12 09:39:01 +01:00 committed by GitHub
parent 2919489fed
commit 7c5098859b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 103 additions and 25 deletions

View File

@ -1,39 +1,108 @@
import { useApi } from '@skolplattformen/hooks'
import React, { useEffect, useState } from 'react'
import { Image as ImageBase, ImageStyle, StyleProp } from 'react-native'
import React, { useCallback, useEffect, useState } from 'react'
import {
Image as ImageBase,
ImageResizeMode,
ImageStyle,
StyleProp,
useWindowDimensions,
View,
} from 'react-native'
interface ImageProps {
src: string
style: StyleProp<ImageStyle>
/**
* Width of component. Defaults to window width
* Used to automatically calculate width
*/
componentWidth?: number
accessibilityIgnoresInvertColors: boolean
resizeMode?: ImageResizeMode
width?: number
height?: number
}
export const Image = ({
src,
style,
componentWidth = 0,
accessibilityIgnoresInvertColors,
resizeMode = 'contain',
}: ImageProps) => {
const { api } = useApi()
const [headers, setHeaders] = useState()
const { width: windowWidth } = useWindowDimensions()
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
const getHeaders = async (url: string) => {
const { headers: newHeaders } = await api.getSession(url)
setHeaders(newHeaders)
}
const debugImageName = getDebugImageName(src)
const prefetchImageInformation = useCallback(
async (url: string) => {
if (!url) return
const { headers: newHeaders } = await api.getSession(url)
console.log('[IMAGE] Getting image dimensions with headers', {
debugImageName,
newHeaders,
})
ImageBase.getSizeWithHeaders(
url,
newHeaders,
(w, h) => {
console.log('[IMAGE] Received image dimensions', {
debugImageName,
w,
h,
})
setDimensions({ width: w, height: h })
setHeaders(newHeaders)
},
(error) => {
console.error('[Image] Failed to get image dimensions', {
debugImageName,
error,
})
}
)
},
[api, debugImageName]
)
useEffect(() => {
getHeaders(src)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [src])
prefetchImageInformation(src)
}, [prefetchImageInformation, src])
return headers ? (
const compWidth = componentWidth || windowWidth
const scale = compWidth / dimensions.width
const scaledWidth = Math.round(dimensions.width * scale)
const scaledHeight = Math.round(dimensions.height * scale)
const imageSource =
resizeMode === 'cover'
? { uri: src, headers }
: { uri: src, headers, height: scaledHeight, width: scaledWidth }
return headers && scaledWidth && scaledHeight ? (
<ImageBase
accessibilityIgnoresInvertColors={accessibilityIgnoresInvertColors}
source={{
uri: src,
headers,
}}
source={imageSource}
resizeMode={resizeMode}
style={style}
/>
) : null
) : (
<View style={style} />
)
}
const getDebugImageName = (src: string) => {
try {
const split = src.split('/')
return split[split.length - 1]
} catch (e: any) {
console.log('FAILED', e.message)
return null
}
}

View File

@ -1,7 +1,8 @@
import { Text } from '@ui-kitten/components'
import React from 'react'
import { Linking, StyleSheet } from 'react-native'
import { Dimensions, Linking, StyleSheet } from 'react-native'
import MarkdownBase, { RenderRules } from 'react-native-markdown-display'
import { Sizing } from '../styles'
import { Image } from './image.component'
interface MarkdownProps {
@ -20,6 +21,9 @@ const rules: RenderRules = {
accessibilityIgnoresInvertColors
key={src}
src={url}
// TODO: Sizing.t5 should not be hardcoded here...
// Maybe measure the width from inside the component instead?
componentWidth={Dimensions.get('window').width - Sizing.t5 * 2}
style={styles.markdownImage}
/>
)
@ -52,5 +56,5 @@ export const Markdown = ({ style, children }: MarkdownProps) => {
}
const styles = StyleSheet.create({
markdownImage: { width: '100%', minHeight: 300 },
markdownImage: { width: '100%', borderRadius: 15 },
})

View File

@ -5,7 +5,7 @@ import { StyleService, Text, useStyleSheet } from '@ui-kitten/components'
import moment from 'moment'
import 'moment/locale/sv'
import React from 'react'
import { ScrollView, View } from 'react-native'
import { Dimensions, ImageStyle, ScrollView, View } from 'react-native'
import { NativeStackNavigationOptions } from 'react-native-screens/native-stack'
import { defaultStackStyling } from '../design/navigationThemes'
import { Layout, Sizing, Typography } from '../styles'
@ -79,8 +79,8 @@ export const NewsItem = ({ route }: NewsItemProps) => {
<Image
accessibilityIgnoresInvertColors={false}
src={newsItem.fullImageUrl}
// @ts-expect-error Fix later on
style={styles.image}
style={styles.image as ImageStyle}
componentWidth={Dimensions.get('screen').width - Sizing.t5 * 2}
/>
)}
</View>
@ -119,7 +119,6 @@ const themedStyles = StyleService.create({
},
image: {
width: '100%',
minHeight: 300,
marginTop: Sizing.t4,
borderRadius: 15,
},

View File

@ -4,7 +4,13 @@ import { NewsItem } from '@skolplattformen/api-skolplattformen'
import { StyleService, useStyleSheet } from '@ui-kitten/components'
import moment from 'moment'
import React, { ReactNode } from 'react'
import { Dimensions, Text, TouchableOpacity, View } from 'react-native'
import {
Dimensions,
ImageStyle,
Text,
TouchableOpacity,
View,
} from 'react-native'
import { Layout, Sizing, Typography } from '../styles'
import { useChild } from './childContext.component'
import { Image } from './image.component'
@ -39,8 +45,8 @@ export const NewsListItem = ({ item, children }: NewsListItemProps) => {
<Image
accessibilityIgnoresInvertColors={false}
src={item.fullImageUrl}
// @ts-expect-error Don't know why this linter breaks
style={styles.image}
resizeMode="cover"
style={styles.image as ImageStyle}
/>
) : null}
<View style={styles.text}>

View File

@ -810,7 +810,7 @@ const data: any = {
intro:
'Vi kommer efter att förskoleklassen är slut arrangera olika vinteraktiviteter genom fridtidsverksamheten.',
body:
'## Vänligen ta med hjälm, skridskor eller stjärtlapp. Alla barn måste ha hjälm på sig samt varma kläder. Vi kommer åka i backen bakom skolbyggnaden samt använda isen som spolats vid Mullsjöskolan. Personal kommer finnas på plats samt att vi erbjuda varm dryck, frukt och lek för de barn som ej har hjälm eller lämpligt åkdon.',
'## Vänligen ta med hjälm, skridskor eller stjärtlapp.\n\n ![Bild](https://images.unsplash.com/photo-1495377701095-00261b767581?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=988&q=80)\n\n Alla barn måste ha hjälm på sig samt varma kläder. Vi kommer åka i backen bakom skolbyggnaden samt använda isen som spolats vid Mullsjöskolan. Personal kommer finnas på plats samt att vi erbjuda varm dryck, frukt och lek för de barn som ej har hjälm eller lämpligt åkdon.',
imageUrl: '6607f9b923edb6f85aa4417bab43c0f8.jpg',
fullImageUrl: 'https://unsplash.com/photos/yB_aiAWkm40',
imageAltText: 'Nyhetsbild. Bildtext ej tillgänglig.',