Skip to content

Commit

Permalink
fix: images cropping on different devices (kolplattformen#524)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
edenstrom and kajetan-kazimierczak authored Nov 12, 2021
1 parent 2919489 commit 7c50988
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 25 deletions.
99 changes: 84 additions & 15 deletions apps/skolplattformen-sthlm/components/image.component.tsx
Original file line number Diff line number Diff line change
@@ -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])

const compWidth = componentWidth || windowWidth

return headers ? (
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
}
}
8 changes: 6 additions & 2 deletions apps/skolplattformen-sthlm/components/markdown.component.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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}
/>
)
Expand Down Expand Up @@ -52,5 +56,5 @@ export const Markdown = ({ style, children }: MarkdownProps) => {
}

const styles = StyleSheet.create({
markdownImage: { width: '100%', minHeight: 300 },
markdownImage: { width: '100%', borderRadius: 15 },
})
7 changes: 3 additions & 4 deletions apps/skolplattformen-sthlm/components/newsItem.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -119,7 +119,6 @@ const themedStyles = StyleService.create({
},
image: {
width: '100%',
minHeight: 300,
marginTop: Sizing.t4,
borderRadius: 15,
},
Expand Down
12 changes: 9 additions & 3 deletions apps/skolplattformen-sthlm/components/newsListItem.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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}>
Expand Down
2 changes: 1 addition & 1 deletion libs/api-skolplattformen/lib/fakeData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
Expand Down

0 comments on commit 7c50988

Please sign in to comment.