From 7c5098859b71f13ffdb9441b81e149b983355d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Edenstr=C3=B6m?= Date: Fri, 12 Nov 2021 09:39:01 +0100 Subject: [PATCH] fix: images cropping on different devices (#524) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- .../components/image.component.tsx | 99 ++++++++++++++++--- .../components/markdown.component.tsx | 8 +- .../components/newsItem.component.tsx | 7 +- .../components/newsListItem.component.tsx | 12 ++- libs/api-skolplattformen/lib/fakeData.ts | 2 +- 5 files changed, 103 insertions(+), 25 deletions(-) diff --git a/apps/skolplattformen-sthlm/components/image.component.tsx b/apps/skolplattformen-sthlm/components/image.component.tsx index 32b05e48..2b17b1eb 100644 --- a/apps/skolplattformen-sthlm/components/image.component.tsx +++ b/apps/skolplattformen-sthlm/components/image.component.tsx @@ -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 + /** + * 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 ? ( - ) : null + ) : ( + + ) +} + +const getDebugImageName = (src: string) => { + try { + const split = src.split('/') + return split[split.length - 1] + } catch (e: any) { + console.log('FAILED', e.message) + return null + } } diff --git a/apps/skolplattformen-sthlm/components/markdown.component.tsx b/apps/skolplattformen-sthlm/components/markdown.component.tsx index 78406a16..5e10d02c 100644 --- a/apps/skolplattformen-sthlm/components/markdown.component.tsx +++ b/apps/skolplattformen-sthlm/components/markdown.component.tsx @@ -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 }, }) diff --git a/apps/skolplattformen-sthlm/components/newsItem.component.tsx b/apps/skolplattformen-sthlm/components/newsItem.component.tsx index edbd006e..da3d8cfa 100644 --- a/apps/skolplattformen-sthlm/components/newsItem.component.tsx +++ b/apps/skolplattformen-sthlm/components/newsItem.component.tsx @@ -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) => { )} @@ -119,7 +119,6 @@ const themedStyles = StyleService.create({ }, image: { width: '100%', - minHeight: 300, marginTop: Sizing.t4, borderRadius: 15, }, diff --git a/apps/skolplattformen-sthlm/components/newsListItem.component.tsx b/apps/skolplattformen-sthlm/components/newsListItem.component.tsx index 5066a3de..226d6686 100644 --- a/apps/skolplattformen-sthlm/components/newsListItem.component.tsx +++ b/apps/skolplattformen-sthlm/components/newsListItem.component.tsx @@ -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) => { ) : null} diff --git a/libs/api-skolplattformen/lib/fakeData.ts b/libs/api-skolplattformen/lib/fakeData.ts index 0b2a32ff..73190533 100644 --- a/libs/api-skolplattformen/lib/fakeData.ts +++ b/libs/api-skolplattformen/lib/fakeData.ts @@ -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.',