Skip to content

Commit 3c52112

Browse files
authored
fix: resolve some issues and improvements to url preview (#6563)
1 parent cc773fe commit 3c52112

File tree

7 files changed

+45747
-42661
lines changed

7 files changed

+45747
-42661
lines changed

app/containers/message/Components/WidthAwareView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export const WidthAwareContext = createContext(0);
55

66
const styles = StyleSheet.create({
77
container: {
8-
flexDirection: 'row'
8+
flex: 1
99
}
1010
});
1111

@@ -17,7 +17,7 @@ export const WidthAwareView = ({ children }: { children: ReactElement }) => {
1717
style={styles.container}
1818
onLayout={ev => {
1919
if (ev.nativeEvent.layout.width) {
20-
setWidth(ev.nativeEvent.layout.width);
20+
setWidth(Math.floor(ev.nativeEvent.layout.width));
2121
}
2222
}}>
2323
<WidthAwareContext.Provider value={width}>{children}</WidthAwareContext.Provider>

app/containers/message/Message.stories.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
FONT_SCALE_LIMIT,
1212
ResponsiveLayoutContext
1313
} from '../../lib/hooks/useResponsiveLayout/useResponsiveLayout';
14+
import { mockedStore as store } from '../../reducers/mockedStore';
15+
import { updateSettings } from '../../actions/settings';
1416

1517
const _theme = 'light';
1618

@@ -34,6 +36,8 @@ const date = new Date(2017, 10, 10, 10);
3436
const longText =
3537
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.';
3638

39+
store.dispatch(updateSettings('API_Embed', true));
40+
3741
const responsiveLayoutProviderLargeFontValue = (fontScale: number) => ({
3842
fontScale,
3943
fontScaleLimited: fontScale,
@@ -1271,7 +1275,7 @@ export const URL = () => (
12711275
urls={[
12721276
{
12731277
url: 'https://rocket.chat',
1274-
image: 'https://rocket.chat/images/blog/post.jpg',
1278+
image: 'https://open.rocket.chat/assets/logo.png',
12751279
title: 'Rocket.Chat - Free, Open Source, Enterprise Team Chat',
12761280
description:
12771281
'Rocket.Chat is the leading open source team chat software solution. Free, unlimited and completely customizable with on-premises and SaaS cloud hosting.'
@@ -1315,7 +1319,7 @@ export const URLLargeFont = () => (
13151319
urls={[
13161320
{
13171321
url: 'https://rocket.chat',
1318-
image: 'https://rocket.chat/images/blog/post.jpg',
1322+
image: 'https://open.rocket.chat/assets/logo.png',
13191323
title: 'Rocket.Chat - Free, Open Source, Enterprise Team Chat',
13201324
description:
13211325
'Rocket.Chat is the leading open source team chat software solution. Free, unlimited and completely customizable with on-premises and SaaS cloud hosting.'

app/containers/message/Message.tsx

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import CallButton from './CallButton';
1919
import { IMessage, IMessageInner, IMessageTouchable } from './interfaces';
2020
import { useTheme } from '../../theme';
2121
import RightIcons from './Components/RightIcons';
22+
import { WidthAwareView } from './Components/WidthAwareView';
2223
import i18n from '../../i18n';
2324
import { getInfoMessage } from './utils';
2425
import MessageTime from './Time';
@@ -28,8 +29,9 @@ const MessageInner = React.memo((props: IMessageInner) => {
2829
const { isLargeFontScale } = useResponsiveLayout();
2930
const showTimeLarge = isLargeFontScale && props.isHeader;
3031

32+
let content;
3133
if (props.isPreview) {
32-
return (
34+
content = (
3335
<>
3436
<User {...props} />
3537
{showTimeLarge ? <MessageTime {...props} /> : null}
@@ -43,7 +45,7 @@ const MessageInner = React.memo((props: IMessageInner) => {
4345
}
4446

4547
if (props.type === 'discussion-created') {
46-
return (
48+
content = (
4749
<>
4850
<User {...props} />
4951
{showTimeLarge ? <MessageTime {...props} /> : null}
@@ -53,7 +55,7 @@ const MessageInner = React.memo((props: IMessageInner) => {
5355
}
5456

5557
if (props.type === 'jitsi_call_started') {
56-
return (
58+
content = (
5759
<>
5860
<User {...props} />
5961
<Content {...props} isInfo />
@@ -64,7 +66,7 @@ const MessageInner = React.memo((props: IMessageInner) => {
6466
}
6567

6668
if (props.blocks && props.blocks.length) {
67-
return (
69+
content = (
6870
<>
6971
<User {...props} />
7072
<Blocks {...props} />
@@ -75,20 +77,24 @@ const MessageInner = React.memo((props: IMessageInner) => {
7577
);
7678
}
7779

78-
return (
79-
<>
80-
<User {...props} />
81-
{showTimeLarge ? <MessageTime {...props} /> : null}
82-
<View style={{ gap: 4 }}>
83-
<Content {...props} />
84-
<Attachments {...props} />
85-
<Urls {...props} />
86-
<Thread {...props} />
87-
<Reactions {...props} />
88-
<Broadcast {...props} />
89-
</View>
90-
</>
91-
);
80+
if (!content) {
81+
content = (
82+
<>
83+
<User {...props} />
84+
{showTimeLarge ? <MessageTime {...props} /> : null}
85+
<View style={{ gap: 4 }}>
86+
<Content {...props} />
87+
<Attachments {...props} />
88+
<Urls {...props} />
89+
<Thread {...props} />
90+
<Reactions {...props} />
91+
<Broadcast {...props} />
92+
</View>
93+
</>
94+
);
95+
}
96+
97+
return <WidthAwareView>{content}</WidthAwareView>;
9298
});
9399
MessageInner.displayName = 'MessageInner';
94100

app/containers/message/Urls.tsx

Lines changed: 39 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { ReactElement, useContext, useEffect, useState } from 'react';
1+
import React, { ReactElement, useContext, useEffect, useLayoutEffect, useState } from 'react';
22
import { StyleSheet, Text, View, ViewStyle } from 'react-native';
33
import Clipboard from '@react-native-clipboard/clipboard';
44
import { Image } from 'expo-image';
@@ -15,19 +15,18 @@ import EventEmitter from '../../lib/methods/helpers/events';
1515
import I18n from '../../i18n';
1616
import MessageContext from './Context';
1717
import { IUrl } from '../../definitions';
18-
import { WidthAwareContext, WidthAwareView } from './Components/WidthAwareView';
18+
import { WidthAwareContext } from './Components/WidthAwareView';
1919

2020
const styles = StyleSheet.create({
2121
container: {
2222
flex: 1,
2323
flexDirection: 'column',
24-
marginTop: 4,
2524
gap: 4
2625
},
2726
textContainer: {
2827
flex: 1,
2928
flexDirection: 'column',
30-
padding: 15,
29+
padding: 12,
3130
justifyContent: 'flex-start',
3231
alignItems: 'flex-start'
3332
},
@@ -40,10 +39,8 @@ const styles = StyleSheet.create({
4039
...sharedStyles.textRegular
4140
},
4241
loading: {
43-
height: 1,
44-
width: 1,
45-
borderWidth: 0,
46-
marginTop: 0
42+
flex: 1,
43+
height: 150
4744
}
4845
});
4946

@@ -66,69 +63,63 @@ const UrlContent = ({ title, description }: { title: string; description: string
6663
};
6764
const UrlImage = ({ image, hasContent }: { image: string; hasContent: boolean }) => {
6865
const { colors } = useTheme();
69-
const [imageLoadedState, setImageLoadedState] = useState<TImageLoadedState>('loading');
7066
const [imageDimensions, setImageDimensions] = useState({ width: 0, height: 0 });
7167
const maxSize = useContext(WidthAwareContext);
7268

73-
useEffect(() => {
74-
if (image) {
69+
useLayoutEffect(() => {
70+
if (image && maxSize) {
7571
Image.loadAsync(image, {
7672
onError: () => {
77-
setImageLoadedState('error');
78-
}
73+
setImageDimensions({ width: -1, height: -1 });
74+
},
75+
maxWidth: maxSize
7976
}).then(image => {
8077
setImageDimensions({ width: image.width, height: image.height });
8178
});
8279
}
83-
}, [image]);
80+
}, [image, maxSize]);
8481

85-
let imageStyle = {};
86-
let containerStyle: ViewStyle = {};
82+
if (!imageDimensions.width || !imageDimensions.height) {
83+
return <View style={styles.loading} />;
84+
}
85+
if (imageDimensions.width === -1) {
86+
return null;
87+
}
8788

88-
if (imageLoadedState === 'done') {
89-
const width = Math.min(imageDimensions.width, maxSize) || 0;
90-
const height = Math.min((imageDimensions.height * ((width * 100) / imageDimensions.width)) / 100, maxSize) || 0;
91-
imageStyle = {
92-
width,
93-
height
94-
};
89+
const width = Math.min(imageDimensions.width, maxSize) || 0;
90+
const height = Math.min((imageDimensions.height * ((width * 100) / imageDimensions.width)) / 100, maxSize) || 0;
91+
const imageStyle = {
92+
width,
93+
height
94+
};
95+
let containerStyle: ViewStyle = {
96+
overflow: 'hidden',
97+
alignItems: 'center',
98+
justifyContent: 'center',
99+
...(imageDimensions.width <= 64 && { width: 64 }),
100+
...(imageDimensions.height <= 64 && { height: 64 })
101+
};
102+
if (!hasContent) {
95103
containerStyle = {
96-
overflow: 'hidden',
97-
alignItems: 'center',
98-
justifyContent: 'center',
99-
...(imageDimensions.width <= 64 && { width: 64 }),
100-
...(imageDimensions.height <= 64 && { height: 64 })
104+
...containerStyle,
105+
borderColor: colors.strokeLight,
106+
borderWidth: 1,
107+
borderRadius: 4
101108
};
102-
if (!hasContent) {
103-
containerStyle = {
104-
...containerStyle,
105-
borderColor: colors.strokeLight,
106-
borderWidth: 1,
107-
borderRadius: 4
108-
};
109-
}
110109
}
111110

112111
return (
113112
<View style={containerStyle}>
114-
<Image
115-
source={{ uri: image }}
116-
style={[imageStyle, imageLoadedState === 'loading' && styles.loading]}
117-
contentFit='contain'
118-
onError={() => setImageLoadedState('error')}
119-
onLoad={() => setImageLoadedState('done')}
120-
/>
113+
<Image source={{ uri: image }} style={imageStyle} contentFit='contain' />
121114
</View>
122115
);
123116
};
124117

125-
type TImageLoadedState = 'loading' | 'done' | 'error';
126-
127118
const Url = ({ url }: { url: IUrl }) => {
128119
const { colors, theme } = useTheme();
129120
const { baseUrl, user } = useContext(MessageContext);
130121
const API_Embed = useAppSelector(state => state.settings.API_Embed);
131-
const [imageUrl, setImageUrl] = useState('');
122+
const [imageUrl, setImageUrl] = useState(url.image);
132123

133124
useEffect(() => {
134125
const verifyUrlIsImage = async () => {
@@ -165,7 +156,7 @@ const Url = ({ url }: { url: IUrl }) => {
165156

166157
const hasContent = !!(url.title || url.description);
167158

168-
if (!url || url?.ignoreParse || !API_Embed || !hasContent) {
159+
if (!url || url?.ignoreParse || !API_Embed) {
169160
return null;
170161
}
171162

@@ -185,11 +176,7 @@ const Url = ({ url }: { url: IUrl }) => {
185176
]}
186177
background={Touchable.Ripple(colors.surfaceNeutral)}>
187178
<>
188-
{imageUrl ? (
189-
<WidthAwareView>
190-
<UrlImage image={imageUrl} hasContent={hasContent} />
191-
</WidthAwareView>
192-
) : null}
179+
{imageUrl ? <UrlImage image={imageUrl} hasContent={hasContent} /> : null}
193180
{hasContent ? <UrlContent title={url.title} description={url.description} /> : null}
194181
</>
195182
</Touchable>

0 commit comments

Comments
 (0)