@sendbird/uikit-react-native-foundation 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/Box/index.js +46 -0
- package/lib/commonjs/components/Box/index.js.map +1 -0
- package/lib/commonjs/components/ImageWithPlaceholder/index.js +92 -0
- package/lib/commonjs/components/ImageWithPlaceholder/index.js.map +1 -0
- package/lib/commonjs/components/PressBox/index.js +60 -0
- package/lib/commonjs/components/PressBox/index.js.map +1 -0
- package/lib/commonjs/index.js +39 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/theme/DarkUIKitTheme.js +220 -179
- package/lib/commonjs/theme/DarkUIKitTheme.js.map +1 -1
- package/lib/commonjs/theme/LightUIKitTheme.js +220 -179
- package/lib/commonjs/theme/LightUIKitTheme.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/ui/Header/index.js +4 -2
- package/lib/commonjs/ui/Header/index.js.map +1 -1
- package/lib/commonjs/ui/OpenChannelMessage/Message.admin.js +40 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.admin.js.map +1 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.file.image.js +57 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.file.image.js.map +1 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.file.js +90 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.file.js.map +1 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.file.video.js +134 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.file.video.js.map +1 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.unknown.js +55 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.unknown.js.map +1 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.user.js +83 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.user.js.map +1 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.user.og.js +140 -0
- package/lib/commonjs/ui/OpenChannelMessage/Message.user.og.js.map +1 -0
- package/lib/commonjs/ui/OpenChannelMessage/MessageContainer.js +136 -0
- package/lib/commonjs/ui/OpenChannelMessage/MessageContainer.js.map +1 -0
- package/lib/commonjs/ui/OpenChannelMessage/index.js +35 -0
- package/lib/commonjs/ui/OpenChannelMessage/index.js.map +1 -0
- package/lib/commonjs/ui/OpenChannelPreview/index.js +134 -0
- package/lib/commonjs/ui/OpenChannelPreview/index.js.map +1 -0
- package/lib/module/components/Box/index.js +33 -0
- package/lib/module/components/Box/index.js.map +1 -0
- package/lib/module/components/ImageWithPlaceholder/index.js +71 -0
- package/lib/module/components/ImageWithPlaceholder/index.js.map +1 -0
- package/lib/module/components/PressBox/index.js +45 -0
- package/lib/module/components/PressBox/index.js.map +1 -0
- package/lib/module/index.js +6 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/theme/DarkUIKitTheme.js +220 -179
- package/lib/module/theme/DarkUIKitTheme.js.map +1 -1
- package/lib/module/theme/LightUIKitTheme.js +220 -179
- package/lib/module/theme/LightUIKitTheme.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/ui/Header/index.js +4 -2
- package/lib/module/ui/Header/index.js.map +1 -1
- package/lib/module/ui/OpenChannelMessage/Message.admin.js +27 -0
- package/lib/module/ui/OpenChannelMessage/Message.admin.js.map +1 -0
- package/lib/module/ui/OpenChannelMessage/Message.file.image.js +41 -0
- package/lib/module/ui/OpenChannelMessage/Message.file.image.js.map +1 -0
- package/lib/module/ui/OpenChannelMessage/Message.file.js +71 -0
- package/lib/module/ui/OpenChannelMessage/Message.file.js.map +1 -0
- package/lib/module/ui/OpenChannelMessage/Message.file.video.js +112 -0
- package/lib/module/ui/OpenChannelMessage/Message.file.video.js.map +1 -0
- package/lib/module/ui/OpenChannelMessage/Message.unknown.js +41 -0
- package/lib/module/ui/OpenChannelMessage/Message.unknown.js.map +1 -0
- package/lib/module/ui/OpenChannelMessage/Message.user.js +67 -0
- package/lib/module/ui/OpenChannelMessage/Message.user.js.map +1 -0
- package/lib/module/ui/OpenChannelMessage/Message.user.og.js +121 -0
- package/lib/module/ui/OpenChannelMessage/Message.user.og.js.map +1 -0
- package/lib/module/ui/OpenChannelMessage/MessageContainer.js +116 -0
- package/lib/module/ui/OpenChannelMessage/MessageContainer.js.map +1 -0
- package/lib/module/ui/OpenChannelMessage/index.js +18 -0
- package/lib/module/ui/OpenChannelMessage/index.js.map +1 -0
- package/lib/module/ui/OpenChannelPreview/index.js +117 -0
- package/lib/module/ui/OpenChannelPreview/index.js.map +1 -0
- package/lib/typescript/src/components/Box/index.d.ts +11 -0
- package/lib/typescript/src/components/ImageWithPlaceholder/index.d.ts +11 -0
- package/lib/typescript/src/components/PressBox/index.d.ts +16 -0
- package/lib/typescript/src/index.d.ts +8 -1
- package/lib/typescript/src/types.d.ts +21 -5
- package/lib/typescript/src/ui/Header/index.d.ts +1 -0
- package/lib/typescript/src/ui/OpenChannelMessage/Message.admin.d.ts +4 -0
- package/lib/typescript/src/ui/OpenChannelMessage/Message.file.d.ts +5 -0
- package/lib/typescript/src/ui/OpenChannelMessage/Message.file.image.d.ts +4 -0
- package/lib/typescript/src/ui/OpenChannelMessage/Message.file.video.d.ts +9 -0
- package/lib/typescript/src/ui/OpenChannelMessage/Message.unknown.d.ts +4 -0
- package/lib/typescript/src/ui/OpenChannelMessage/Message.user.d.ts +5 -0
- package/lib/typescript/src/ui/OpenChannelMessage/Message.user.og.d.ts +5 -0
- package/lib/typescript/src/ui/OpenChannelMessage/MessageContainer.d.ts +7 -0
- package/lib/typescript/src/ui/OpenChannelMessage/index.d.ts +136 -0
- package/lib/typescript/src/ui/OpenChannelPreview/index.d.ts +10 -0
- package/package.json +4 -4
- package/src/components/Box/index.tsx +65 -0
- package/src/components/ImageWithPlaceholder/index.tsx +83 -0
- package/src/components/PressBox/index.tsx +53 -0
- package/src/index.ts +8 -1
- package/src/theme/DarkUIKitTheme.ts +213 -171
- package/src/theme/LightUIKitTheme.ts +213 -171
- package/src/types.ts +41 -6
- package/src/ui/Header/index.tsx +7 -2
- package/src/ui/OpenChannelMessage/Message.admin.tsx +24 -0
- package/src/ui/OpenChannelMessage/Message.file.image.tsx +34 -0
- package/src/ui/OpenChannelMessage/Message.file.tsx +67 -0
- package/src/ui/OpenChannelMessage/Message.file.video.tsx +93 -0
- package/src/ui/OpenChannelMessage/Message.unknown.tsx +31 -0
- package/src/ui/OpenChannelMessage/Message.user.og.tsx +120 -0
- package/src/ui/OpenChannelMessage/Message.user.tsx +61 -0
- package/src/ui/OpenChannelMessage/MessageContainer.tsx +121 -0
- package/src/ui/OpenChannelMessage/index.ts +42 -0
- package/src/ui/OpenChannelPreview/index.tsx +97 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { SendbirdFileMessage, getFileTypeFromMessage } from '@sendbird/uikit-utils';
|
|
4
|
+
|
|
5
|
+
import Box from '../../components/Box';
|
|
6
|
+
import Icon from '../../components/Icon';
|
|
7
|
+
import PressBox from '../../components/PressBox';
|
|
8
|
+
import Text from '../../components/Text';
|
|
9
|
+
import createStyleSheet from '../../styles/createStyleSheet';
|
|
10
|
+
import useUIKitTheme from '../../theme/useUIKitTheme';
|
|
11
|
+
import MessageContainer from './MessageContainer';
|
|
12
|
+
import type { OpenChannelMessageProps } from './index';
|
|
13
|
+
|
|
14
|
+
const iconMapper = { audio: 'file-audio', image: 'photo', video: 'play', file: 'file-document' } as const;
|
|
15
|
+
|
|
16
|
+
type Props = {};
|
|
17
|
+
const FileMessage = (props: OpenChannelMessageProps<SendbirdFileMessage, Props>) => {
|
|
18
|
+
const { colors } = useUIKitTheme();
|
|
19
|
+
const { onPress, onLongPress, ...rest } = props;
|
|
20
|
+
const type = getFileTypeFromMessage(props.message);
|
|
21
|
+
const color = colors.ui.openChannelMessage.default;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<MessageContainer {...rest}>
|
|
25
|
+
<PressBox onPress={onPress} onLongPress={onLongPress}>
|
|
26
|
+
{({ pressed }) => {
|
|
27
|
+
return (
|
|
28
|
+
<Box
|
|
29
|
+
padding={8}
|
|
30
|
+
borderRadius={8}
|
|
31
|
+
flexDirection={'row'}
|
|
32
|
+
alignItems={'center'}
|
|
33
|
+
justifyContent={'flex-start'}
|
|
34
|
+
style={{ backgroundColor: pressed ? color.pressed.bubbleBackground : color.enabled.bubbleBackground }}
|
|
35
|
+
>
|
|
36
|
+
<Box
|
|
37
|
+
padding={4}
|
|
38
|
+
marginRight={8}
|
|
39
|
+
borderRadius={8}
|
|
40
|
+
alignItems={'flex-start'}
|
|
41
|
+
backgroundColor={colors.background}
|
|
42
|
+
>
|
|
43
|
+
<Icon icon={iconMapper[type]} size={32} />
|
|
44
|
+
</Box>
|
|
45
|
+
<Text
|
|
46
|
+
body3
|
|
47
|
+
numberOfLines={1}
|
|
48
|
+
ellipsizeMode={'middle'}
|
|
49
|
+
color={color.enabled.textMsg}
|
|
50
|
+
style={styles.fileName}
|
|
51
|
+
>
|
|
52
|
+
{props.strings?.fileName || props.message.name}
|
|
53
|
+
</Text>
|
|
54
|
+
</Box>
|
|
55
|
+
);
|
|
56
|
+
}}
|
|
57
|
+
</PressBox>
|
|
58
|
+
</MessageContainer>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const styles = createStyleSheet({
|
|
63
|
+
fileName: {
|
|
64
|
+
flexShrink: 1,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
export default FileMessage;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { SendbirdFileMessage } from '@sendbird/uikit-utils';
|
|
4
|
+
import { getAvailableUriFromFileMessage } from '@sendbird/uikit-utils';
|
|
5
|
+
|
|
6
|
+
import Box from '../../components/Box';
|
|
7
|
+
import Icon from '../../components/Icon';
|
|
8
|
+
import ImageWithPlaceholder from '../../components/ImageWithPlaceholder';
|
|
9
|
+
import PressBox from '../../components/PressBox';
|
|
10
|
+
import createStyleSheet from '../../styles/createStyleSheet';
|
|
11
|
+
import useUIKitTheme from '../../theme/useUIKitTheme';
|
|
12
|
+
import MessageContainer from './MessageContainer';
|
|
13
|
+
import type { OpenChannelMessageProps } from './index';
|
|
14
|
+
|
|
15
|
+
type Props = {
|
|
16
|
+
fetchThumbnailFromVideoSource: (uri: string) => Promise<{ path: string } | null>;
|
|
17
|
+
};
|
|
18
|
+
const VideoFileMessage = (props: OpenChannelMessageProps<SendbirdFileMessage, Props>) => {
|
|
19
|
+
const { colors, palette } = useUIKitTheme();
|
|
20
|
+
const { onPress, onLongPress, ...rest } = props;
|
|
21
|
+
const uri = getAvailableUriFromFileMessage(props.message);
|
|
22
|
+
const { thumbnail, loading } = useRetry(() => props.fetchThumbnailFromVideoSource(uri));
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<MessageContainer {...rest}>
|
|
26
|
+
<PressBox style={styles.container} activeOpacity={0.8} onPress={onPress} onLongPress={onLongPress}>
|
|
27
|
+
<Box borderRadius={8} overflow={'hidden'} style={styles.container}>
|
|
28
|
+
{loading ? (
|
|
29
|
+
<Box backgroundColor={colors.onBackground04} style={{ width: '100%', height: '100%' }} />
|
|
30
|
+
) : (
|
|
31
|
+
<ImageWithPlaceholder source={{ uri: thumbnail ?? 'invalid-image' }} width={'100%'} height={'100%'} />
|
|
32
|
+
)}
|
|
33
|
+
|
|
34
|
+
{(loading || thumbnail !== null) && (
|
|
35
|
+
<Box style={styles.iconContainer} alignItems={'center'} justifyContent={'center'}>
|
|
36
|
+
<Icon
|
|
37
|
+
icon={'play'}
|
|
38
|
+
size={28}
|
|
39
|
+
color={palette.onBackgroundLight02}
|
|
40
|
+
containerStyle={[styles.playIcon, { backgroundColor: palette.onBackgroundDark01 }]}
|
|
41
|
+
/>
|
|
42
|
+
</Box>
|
|
43
|
+
)}
|
|
44
|
+
</Box>
|
|
45
|
+
</PressBox>
|
|
46
|
+
</MessageContainer>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
const useRetry = (fetch: () => Promise<{ path: string } | null>, retryCount = 5) => {
|
|
50
|
+
const [state, setState] = useState({ thumbnail: null as null | string, loading: true });
|
|
51
|
+
const retryCountRef = useRef(0);
|
|
52
|
+
const retryTimeoutRef = useRef<NodeJS.Timeout>();
|
|
53
|
+
const fetchThumbnail = useRef(fetch);
|
|
54
|
+
fetchThumbnail.current = fetch;
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!state.thumbnail) {
|
|
58
|
+
const reloadReservation = () => {
|
|
59
|
+
if (retryCountRef.current < retryCount) {
|
|
60
|
+
retryTimeoutRef.current = setTimeout(() => {
|
|
61
|
+
retryCountRef.current++;
|
|
62
|
+
reloadReservation();
|
|
63
|
+
fetchThumbnail.current().then((result) => {
|
|
64
|
+
setState({ loading: false, thumbnail: result?.path ?? null });
|
|
65
|
+
});
|
|
66
|
+
}, retryCountRef.current * 5000);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return reloadReservation();
|
|
71
|
+
} else {
|
|
72
|
+
return clearTimeout(retryTimeoutRef.current);
|
|
73
|
+
}
|
|
74
|
+
}, [state.thumbnail]);
|
|
75
|
+
|
|
76
|
+
return state;
|
|
77
|
+
};
|
|
78
|
+
const styles = createStyleSheet({
|
|
79
|
+
container: {
|
|
80
|
+
maxWidth: 296,
|
|
81
|
+
height: 196,
|
|
82
|
+
},
|
|
83
|
+
iconContainer: {
|
|
84
|
+
position: 'absolute',
|
|
85
|
+
width: '100%',
|
|
86
|
+
height: '100%',
|
|
87
|
+
},
|
|
88
|
+
playIcon: {
|
|
89
|
+
padding: 10,
|
|
90
|
+
borderRadius: 50,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
export default VideoFileMessage;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { SendbirdMessage } from '@sendbird/uikit-utils';
|
|
4
|
+
|
|
5
|
+
import PressBox from '../../components/PressBox';
|
|
6
|
+
import Text from '../../components/Text';
|
|
7
|
+
import useUIKitTheme from '../../theme/useUIKitTheme';
|
|
8
|
+
import MessageContainer from './MessageContainer';
|
|
9
|
+
import type { OpenChannelMessageProps } from './index';
|
|
10
|
+
|
|
11
|
+
const UnknownMessage = (props: OpenChannelMessageProps<SendbirdMessage>) => {
|
|
12
|
+
const { colors } = useUIKitTheme();
|
|
13
|
+
const { onPress, onLongPress, ...rest } = props;
|
|
14
|
+
const color = colors.ui.openChannelMessage.default;
|
|
15
|
+
return (
|
|
16
|
+
<PressBox onPress={onPress} onLongPress={onLongPress}>
|
|
17
|
+
{({ pressed }) => (
|
|
18
|
+
<MessageContainer pressed={pressed} {...rest}>
|
|
19
|
+
<Text body3 color={color.enabled.textMsg}>
|
|
20
|
+
{props.strings?.unknownTitle ?? '(Unknown message type)'}
|
|
21
|
+
</Text>
|
|
22
|
+
<Text body3 color={color.enabled.textMsgPostfix}>
|
|
23
|
+
{props.strings?.unknownDescription ?? 'Cannot read this message.'}
|
|
24
|
+
</Text>
|
|
25
|
+
</MessageContainer>
|
|
26
|
+
)}
|
|
27
|
+
</PressBox>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default UnknownMessage;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { SendbirdUserMessage } from '@sendbird/uikit-utils';
|
|
4
|
+
import { urlRegexRough } from '@sendbird/uikit-utils';
|
|
5
|
+
|
|
6
|
+
import Box from '../../components/Box';
|
|
7
|
+
import ImageWithPlaceholder from '../../components/ImageWithPlaceholder';
|
|
8
|
+
import PressBox from '../../components/PressBox';
|
|
9
|
+
import RegexText from '../../components/RegexText';
|
|
10
|
+
import Text from '../../components/Text';
|
|
11
|
+
import createStyleSheet from '../../styles/createStyleSheet';
|
|
12
|
+
import useUIKitTheme from '../../theme/useUIKitTheme';
|
|
13
|
+
import MessageContainer from './MessageContainer';
|
|
14
|
+
import type { OpenChannelMessageProps } from './index';
|
|
15
|
+
|
|
16
|
+
type Props = {};
|
|
17
|
+
const OpenGraphUserMessage = (props: OpenChannelMessageProps<SendbirdUserMessage, Props>) => {
|
|
18
|
+
const { colors } = useUIKitTheme();
|
|
19
|
+
const { onPress, onLongPress, onPressURL, ...rest } = props;
|
|
20
|
+
const color = colors.ui.openChannelMessage.default;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Box>
|
|
24
|
+
<PressBox onPress={onPress} onLongPress={onLongPress}>
|
|
25
|
+
{({ pressed }) => (
|
|
26
|
+
<MessageContainer pressed={pressed} {...rest}>
|
|
27
|
+
<Text body3 color={color.enabled.textMsg}>
|
|
28
|
+
<RegexText
|
|
29
|
+
body3
|
|
30
|
+
color={color.enabled.textMsg}
|
|
31
|
+
patterns={[
|
|
32
|
+
{
|
|
33
|
+
regex: urlRegexRough,
|
|
34
|
+
replacer({ match, parentProps, keyPrefix, index }) {
|
|
35
|
+
return (
|
|
36
|
+
<Text
|
|
37
|
+
{...parentProps}
|
|
38
|
+
key={`${keyPrefix}-${index}`}
|
|
39
|
+
onPress={onPressURL}
|
|
40
|
+
onLongPress={onLongPress}
|
|
41
|
+
color={colors.primary}
|
|
42
|
+
style={parentProps?.style}
|
|
43
|
+
>
|
|
44
|
+
{match}
|
|
45
|
+
</Text>
|
|
46
|
+
);
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
]}
|
|
50
|
+
>
|
|
51
|
+
{props.message.message}
|
|
52
|
+
</RegexText>
|
|
53
|
+
{Boolean(props.message.updatedAt) && (
|
|
54
|
+
<Text body3 color={color.enabled.textMsgPostfix}>
|
|
55
|
+
{props.strings?.edited ?? ' (edited)'}
|
|
56
|
+
</Text>
|
|
57
|
+
)}
|
|
58
|
+
</Text>
|
|
59
|
+
</MessageContainer>
|
|
60
|
+
)}
|
|
61
|
+
</PressBox>
|
|
62
|
+
{props.message.ogMetaData && (
|
|
63
|
+
<MessageContainer {...rest} grouped>
|
|
64
|
+
<PressBox style={styles.ogContainer} onPress={onPressURL} onLongPress={onLongPress}>
|
|
65
|
+
{({ pressed }) =>
|
|
66
|
+
props.message.ogMetaData && (
|
|
67
|
+
<Box
|
|
68
|
+
padding={8}
|
|
69
|
+
borderRadius={8}
|
|
70
|
+
style={styles.ogContainer}
|
|
71
|
+
backgroundColor={pressed ? color.pressed.bubbleBackground : color.enabled.bubbleBackground}
|
|
72
|
+
>
|
|
73
|
+
<Text numberOfLines={1} caption2 color={colors.onBackground02} style={styles.ogUrl}>
|
|
74
|
+
{props.message.ogMetaData.url}
|
|
75
|
+
</Text>
|
|
76
|
+
|
|
77
|
+
<Text numberOfLines={2} body2 color={colors.primary} style={styles.ogTitle}>
|
|
78
|
+
{props.message.ogMetaData.title}
|
|
79
|
+
</Text>
|
|
80
|
+
|
|
81
|
+
{Boolean(props.message.ogMetaData.description) && (
|
|
82
|
+
<Text numberOfLines={2} caption2 color={colors.onBackground01}>
|
|
83
|
+
{props.message.ogMetaData.description}
|
|
84
|
+
</Text>
|
|
85
|
+
)}
|
|
86
|
+
|
|
87
|
+
{Boolean(props.message.ogMetaData.defaultImage) && (
|
|
88
|
+
<ImageWithPlaceholder
|
|
89
|
+
style={styles.ogImage}
|
|
90
|
+
source={{ uri: props.message.ogMetaData.defaultImage.url }}
|
|
91
|
+
/>
|
|
92
|
+
)}
|
|
93
|
+
</Box>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
</PressBox>
|
|
97
|
+
</MessageContainer>
|
|
98
|
+
)}
|
|
99
|
+
</Box>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const styles = createStyleSheet({
|
|
104
|
+
ogContainer: {
|
|
105
|
+
maxWidth: 296,
|
|
106
|
+
},
|
|
107
|
+
ogUrl: {
|
|
108
|
+
marginBottom: 4,
|
|
109
|
+
},
|
|
110
|
+
ogTitle: {
|
|
111
|
+
marginBottom: 8,
|
|
112
|
+
},
|
|
113
|
+
ogImage: {
|
|
114
|
+
width: '100%',
|
|
115
|
+
height: 156,
|
|
116
|
+
marginTop: 12,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
export default OpenGraphUserMessage;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { SendbirdUserMessage } from '@sendbird/uikit-utils';
|
|
4
|
+
import { urlRegexStrict } from '@sendbird/uikit-utils';
|
|
5
|
+
|
|
6
|
+
import PressBox from '../../components/PressBox';
|
|
7
|
+
import RegexText from '../../components/RegexText';
|
|
8
|
+
import Text from '../../components/Text';
|
|
9
|
+
import useUIKitTheme from '../../theme/useUIKitTheme';
|
|
10
|
+
import MessageContainer from './MessageContainer';
|
|
11
|
+
import type { OpenChannelMessageProps } from './index';
|
|
12
|
+
|
|
13
|
+
type Props = {};
|
|
14
|
+
const UserMessage = (props: OpenChannelMessageProps<SendbirdUserMessage, Props>) => {
|
|
15
|
+
const { colors } = useUIKitTheme();
|
|
16
|
+
const { onPress, onLongPress, onPressURL, ...rest } = props;
|
|
17
|
+
const color = colors.ui.openChannelMessage.default;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<PressBox onPress={onPress} onLongPress={onLongPress}>
|
|
21
|
+
{({ pressed }) => (
|
|
22
|
+
<MessageContainer pressed={pressed} {...rest}>
|
|
23
|
+
<Text body3 color={color.enabled.textMsg}>
|
|
24
|
+
<RegexText
|
|
25
|
+
body3
|
|
26
|
+
color={color.enabled.textMsg}
|
|
27
|
+
patterns={[
|
|
28
|
+
{
|
|
29
|
+
regex: urlRegexStrict,
|
|
30
|
+
replacer({ match, parentProps, keyPrefix, index }) {
|
|
31
|
+
return (
|
|
32
|
+
<Text
|
|
33
|
+
{...parentProps}
|
|
34
|
+
key={`${keyPrefix}-${index}`}
|
|
35
|
+
onPress={onPressURL}
|
|
36
|
+
onLongPress={onLongPress}
|
|
37
|
+
color={colors.primary}
|
|
38
|
+
style={parentProps?.style}
|
|
39
|
+
>
|
|
40
|
+
{match}
|
|
41
|
+
</Text>
|
|
42
|
+
);
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
]}
|
|
46
|
+
>
|
|
47
|
+
{props.message.message}
|
|
48
|
+
</RegexText>
|
|
49
|
+
{Boolean(props.message.updatedAt) && (
|
|
50
|
+
<Text body3 color={color.enabled.textMsgPostfix}>
|
|
51
|
+
{props.strings?.edited ?? ' (edited)'}
|
|
52
|
+
</Text>
|
|
53
|
+
)}
|
|
54
|
+
</Text>
|
|
55
|
+
</MessageContainer>
|
|
56
|
+
)}
|
|
57
|
+
</PressBox>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default UserMessage;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { SendingStatus } from '@sendbird/chat/message';
|
|
4
|
+
import type { SendbirdMessage } from '@sendbird/uikit-utils';
|
|
5
|
+
import { getMessageTimeFormat } from '@sendbird/uikit-utils';
|
|
6
|
+
|
|
7
|
+
import Box from '../../components/Box';
|
|
8
|
+
import Icon from '../../components/Icon';
|
|
9
|
+
import PressBox from '../../components/PressBox';
|
|
10
|
+
import Text from '../../components/Text';
|
|
11
|
+
import createStyleSheet from '../../styles/createStyleSheet';
|
|
12
|
+
import useUIKitTheme from '../../theme/useUIKitTheme';
|
|
13
|
+
import Avatar from '../Avatar';
|
|
14
|
+
import LoadingSpinner from '../LoadingSpinner';
|
|
15
|
+
import type { OpenChannelMessageProps } from './index';
|
|
16
|
+
|
|
17
|
+
type Props = {
|
|
18
|
+
pressed?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const MessageContainer = ({
|
|
22
|
+
children,
|
|
23
|
+
channel,
|
|
24
|
+
grouped,
|
|
25
|
+
pressed,
|
|
26
|
+
...props
|
|
27
|
+
}: OpenChannelMessageProps<SendbirdMessage, Props>) => {
|
|
28
|
+
const { colors } = useUIKitTheme();
|
|
29
|
+
const color = colors.ui.openChannelMessage.default;
|
|
30
|
+
|
|
31
|
+
const renderSendingStatus = () => {
|
|
32
|
+
if (!('sendingStatus' in props.message)) return null;
|
|
33
|
+
|
|
34
|
+
switch (props.message.sendingStatus) {
|
|
35
|
+
case SendingStatus.PENDING: {
|
|
36
|
+
return (
|
|
37
|
+
<SendingStatusContainer>
|
|
38
|
+
<LoadingSpinner color={colors.primary} size={16} />
|
|
39
|
+
</SendingStatusContainer>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
case SendingStatus.FAILED: {
|
|
43
|
+
return (
|
|
44
|
+
<SendingStatusContainer>
|
|
45
|
+
<Icon icon={'error'} color={colors.error} size={16} />
|
|
46
|
+
</SendingStatusContainer>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
default: {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Box
|
|
57
|
+
flexDirection={'row'}
|
|
58
|
+
paddingVertical={grouped ? 5 : 6}
|
|
59
|
+
paddingLeft={12}
|
|
60
|
+
paddingRight={12}
|
|
61
|
+
backgroundColor={pressed ? color.pressed.background : color.enabled.background}
|
|
62
|
+
>
|
|
63
|
+
<Box marginRight={12}>
|
|
64
|
+
{!grouped && 'sender' in props.message ? (
|
|
65
|
+
<PressBox onPress={props.onPressAvatar}>
|
|
66
|
+
<Avatar size={styles.avatar.width} uri={props.message.sender.profileUrl} />
|
|
67
|
+
</PressBox>
|
|
68
|
+
) : (
|
|
69
|
+
<Box style={styles.avatar} />
|
|
70
|
+
)}
|
|
71
|
+
</Box>
|
|
72
|
+
<Box flexShrink={1} flex={1} flexDirection={'column'} alignItems={'flex-start'}>
|
|
73
|
+
{!grouped && 'sender' in props.message && (
|
|
74
|
+
<Box flexDirection={'row'} alignItems={'center'} marginBottom={2}>
|
|
75
|
+
<Box marginRight={4} flexShrink={1}>
|
|
76
|
+
<Text
|
|
77
|
+
caption1
|
|
78
|
+
ellipsizeMode={'middle'}
|
|
79
|
+
numberOfLines={1}
|
|
80
|
+
color={
|
|
81
|
+
channel.isOperator(props.message.sender.userId)
|
|
82
|
+
? color.enabled.textOperator
|
|
83
|
+
: color.enabled.textSenderName
|
|
84
|
+
}
|
|
85
|
+
>
|
|
86
|
+
{props.strings?.senderName ?? props.message.sender.nickname}
|
|
87
|
+
</Text>
|
|
88
|
+
</Box>
|
|
89
|
+
<Box>
|
|
90
|
+
<Text caption4 color={color.enabled.textTime}>
|
|
91
|
+
{props.strings?.sentDate ?? getMessageTimeFormat(new Date(props.message.createdAt))}
|
|
92
|
+
</Text>
|
|
93
|
+
</Box>
|
|
94
|
+
</Box>
|
|
95
|
+
)}
|
|
96
|
+
<Box style={styles.message}>{children}</Box>
|
|
97
|
+
|
|
98
|
+
{renderSendingStatus()}
|
|
99
|
+
</Box>
|
|
100
|
+
</Box>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const SendingStatusContainer = ({ children }: { children: React.ReactElement }) => {
|
|
105
|
+
return (
|
|
106
|
+
<Box flexDirection={'row'}>
|
|
107
|
+
<Box marginTop={2}>{children}</Box>
|
|
108
|
+
</Box>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const styles = createStyleSheet({
|
|
113
|
+
avatar: {
|
|
114
|
+
width: 28,
|
|
115
|
+
},
|
|
116
|
+
message: {
|
|
117
|
+
width: '100%',
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
export default MessageContainer;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { SendbirdMessage, SendbirdOpenChannel } from '@sendbird/uikit-utils';
|
|
4
|
+
|
|
5
|
+
import AdminMessage from './Message.admin';
|
|
6
|
+
import FileMessage from './Message.file';
|
|
7
|
+
import ImageFileMessage from './Message.file.image';
|
|
8
|
+
import VideoFileMessage from './Message.file.video';
|
|
9
|
+
import UnknownMessage from './Message.unknown';
|
|
10
|
+
import UserMessage from './Message.user';
|
|
11
|
+
import OpenGraphUserMessage from './Message.user.og';
|
|
12
|
+
|
|
13
|
+
export type OpenChannelMessageProps<T extends SendbirdMessage, AdditionalProps = unknown> = {
|
|
14
|
+
channel: SendbirdOpenChannel;
|
|
15
|
+
message: T;
|
|
16
|
+
strings?: {
|
|
17
|
+
senderName?: string;
|
|
18
|
+
sentDate?: string;
|
|
19
|
+
edited?: string;
|
|
20
|
+
fileName?: string;
|
|
21
|
+
unknownTitle?: string;
|
|
22
|
+
unknownDescription?: string;
|
|
23
|
+
};
|
|
24
|
+
children?: React.ReactNode;
|
|
25
|
+
grouped?: boolean;
|
|
26
|
+
onPress?: () => void;
|
|
27
|
+
onLongPress?: () => void;
|
|
28
|
+
onPressAvatar?: () => void;
|
|
29
|
+
onPressURL?: () => void;
|
|
30
|
+
} & AdditionalProps;
|
|
31
|
+
|
|
32
|
+
const OpenChannelMessage = {
|
|
33
|
+
User: UserMessage,
|
|
34
|
+
OpenGraphUser: OpenGraphUserMessage,
|
|
35
|
+
File: FileMessage,
|
|
36
|
+
ImageFile: ImageFileMessage,
|
|
37
|
+
VideoFile: VideoFileMessage,
|
|
38
|
+
Admin: AdminMessage,
|
|
39
|
+
Unknown: UnknownMessage,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default OpenChannelMessage;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { conditionChaining, truncatedCount } from '@sendbird/uikit-utils';
|
|
4
|
+
|
|
5
|
+
import Box from '../../components/Box';
|
|
6
|
+
import Icon from '../../components/Icon';
|
|
7
|
+
import Image from '../../components/Image';
|
|
8
|
+
import Text from '../../components/Text';
|
|
9
|
+
import createStyleSheet from '../../styles/createStyleSheet';
|
|
10
|
+
import useUIKitTheme from '../../theme/useUIKitTheme';
|
|
11
|
+
|
|
12
|
+
type Props = {
|
|
13
|
+
customCover?: React.ReactElement;
|
|
14
|
+
coverUrl: string;
|
|
15
|
+
title: string;
|
|
16
|
+
participantsCount?: number;
|
|
17
|
+
frozen?: boolean;
|
|
18
|
+
};
|
|
19
|
+
const OpenChannelPreview = ({ customCover, coverUrl, participantsCount = 0, title, frozen }: Props) => {
|
|
20
|
+
const { colors } = useUIKitTheme();
|
|
21
|
+
const color = colors.ui.openChannelPreview.default.none;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Box
|
|
25
|
+
backgroundColor={color.background}
|
|
26
|
+
width={'100%'}
|
|
27
|
+
height={62}
|
|
28
|
+
flexDirection={'row'}
|
|
29
|
+
alignItems={'center'}
|
|
30
|
+
paddingHorizontal={16}
|
|
31
|
+
>
|
|
32
|
+
<Box
|
|
33
|
+
width={styles.channelCover.width}
|
|
34
|
+
height={styles.channelCover.height}
|
|
35
|
+
borderRadius={styles.channelCover.width}
|
|
36
|
+
overflow={'hidden'}
|
|
37
|
+
marginRight={16}
|
|
38
|
+
>
|
|
39
|
+
{conditionChaining(
|
|
40
|
+
[Boolean(customCover)],
|
|
41
|
+
[
|
|
42
|
+
customCover,
|
|
43
|
+
<Image
|
|
44
|
+
resizeMode={'cover'}
|
|
45
|
+
style={[styles.channelCover, { backgroundColor: color.coverBackground }]}
|
|
46
|
+
source={{ uri: coverUrl }}
|
|
47
|
+
/>,
|
|
48
|
+
],
|
|
49
|
+
)}
|
|
50
|
+
</Box>
|
|
51
|
+
<Box flex={1} height={'100%'} justifyContent={'center'}>
|
|
52
|
+
<Box flexDirection={'row'} flexShrink={1} marginBottom={4} alignItems={'center'}>
|
|
53
|
+
<Text subtitle1 style={styles.channelInfoTitle} numberOfLines={1} color={color.textTitle}>
|
|
54
|
+
{title}
|
|
55
|
+
</Text>
|
|
56
|
+
{frozen && <Icon size={16} icon={'freeze'} color={color.frozenIcon} containerStyle={styles.marginLeft} />}
|
|
57
|
+
</Box>
|
|
58
|
+
<Box flexDirection={'row'} flexShrink={1} alignItems={'center'} justifyContent={'flex-start'}>
|
|
59
|
+
<Box flexDirection={'row'} alignItems={'center'}>
|
|
60
|
+
<Icon size={16} icon={'members'} color={color.participantsIcon} containerStyle={styles.marginRight} />
|
|
61
|
+
<Text caption2 color={color.textParticipants}>
|
|
62
|
+
{truncatedCount(participantsCount, 999)}
|
|
63
|
+
</Text>
|
|
64
|
+
</Box>
|
|
65
|
+
</Box>
|
|
66
|
+
<Separator color={color.separator} />
|
|
67
|
+
</Box>
|
|
68
|
+
</Box>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const Separator = ({ color }: { color: string }) => <Box style={[styles.separator, { backgroundColor: color }]} />;
|
|
73
|
+
|
|
74
|
+
const styles = createStyleSheet({
|
|
75
|
+
channelCover: {
|
|
76
|
+
width: 32,
|
|
77
|
+
height: 32,
|
|
78
|
+
},
|
|
79
|
+
channelInfoTitle: {
|
|
80
|
+
flexShrink: 1,
|
|
81
|
+
},
|
|
82
|
+
marginRight: {
|
|
83
|
+
marginRight: 4,
|
|
84
|
+
},
|
|
85
|
+
marginLeft: {
|
|
86
|
+
marginLeft: 4,
|
|
87
|
+
},
|
|
88
|
+
separator: {
|
|
89
|
+
position: 'absolute',
|
|
90
|
+
left: 0,
|
|
91
|
+
right: -16,
|
|
92
|
+
bottom: 0,
|
|
93
|
+
height: 1,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
export default OpenChannelPreview;
|