Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: images cropping on different devices #524

Merged
merged 5 commits into from
Nov 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
}
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 },
})
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
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