@sendbird/uikit-react-native-foundation 3.0.4 → 3.1.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.
Files changed (96) hide show
  1. package/lib/commonjs/components/Icon/index.js +12 -0
  2. package/lib/commonjs/components/Icon/index.js.map +1 -1
  3. package/lib/commonjs/components/VideoThumbnail/index.js +115 -0
  4. package/lib/commonjs/components/VideoThumbnail/index.js.map +1 -0
  5. package/lib/commonjs/index.js +7 -0
  6. package/lib/commonjs/index.js.map +1 -1
  7. package/lib/commonjs/theme/DarkUIKitTheme.js +2 -1
  8. package/lib/commonjs/theme/DarkUIKitTheme.js.map +1 -1
  9. package/lib/commonjs/theme/LightUIKitTheme.js +2 -1
  10. package/lib/commonjs/theme/LightUIKitTheme.js.map +1 -1
  11. package/lib/commonjs/types.js.map +1 -1
  12. package/lib/commonjs/ui/BottomSheet/index.js +1 -0
  13. package/lib/commonjs/ui/BottomSheet/index.js.map +1 -1
  14. package/lib/commonjs/ui/Dialog/DialogSheet.js +4 -3
  15. package/lib/commonjs/ui/Dialog/DialogSheet.js.map +1 -1
  16. package/lib/commonjs/ui/GroupChannelMessage/Message.file.image.js +1 -1
  17. package/lib/commonjs/ui/GroupChannelMessage/Message.file.image.js.map +1 -1
  18. package/lib/commonjs/ui/GroupChannelMessage/Message.file.js +6 -9
  19. package/lib/commonjs/ui/GroupChannelMessage/Message.file.js.map +1 -1
  20. package/lib/commonjs/ui/GroupChannelMessage/Message.file.video.js +10 -72
  21. package/lib/commonjs/ui/GroupChannelMessage/Message.file.video.js.map +1 -1
  22. package/lib/commonjs/ui/GroupChannelMessage/MessageContainer.js +7 -5
  23. package/lib/commonjs/ui/GroupChannelMessage/MessageContainer.js.map +1 -1
  24. package/lib/commonjs/ui/GroupChannelMessage/MessageOpenGraph.js +2 -2
  25. package/lib/commonjs/ui/GroupChannelMessage/MessageOpenGraph.js.map +1 -1
  26. package/lib/commonjs/ui/GroupChannelMessage/index.js.map +1 -1
  27. package/lib/commonjs/ui/OpenChannelMessage/Message.file.image.js +1 -1
  28. package/lib/commonjs/ui/OpenChannelMessage/Message.file.image.js.map +1 -1
  29. package/lib/commonjs/ui/OpenChannelMessage/Message.file.js +2 -8
  30. package/lib/commonjs/ui/OpenChannelMessage/Message.file.js.map +1 -1
  31. package/lib/commonjs/ui/OpenChannelMessage/Message.file.video.js +11 -78
  32. package/lib/commonjs/ui/OpenChannelMessage/Message.file.video.js.map +1 -1
  33. package/lib/commonjs/ui/OpenChannelMessage/Message.user.og.js +1 -1
  34. package/lib/commonjs/ui/OpenChannelMessage/Message.user.og.js.map +1 -1
  35. package/lib/module/components/Icon/index.js +12 -0
  36. package/lib/module/components/Icon/index.js.map +1 -1
  37. package/lib/module/components/VideoThumbnail/index.js +105 -0
  38. package/lib/module/components/VideoThumbnail/index.js.map +1 -0
  39. package/lib/module/index.js +1 -0
  40. package/lib/module/index.js.map +1 -1
  41. package/lib/module/theme/DarkUIKitTheme.js +2 -1
  42. package/lib/module/theme/DarkUIKitTheme.js.map +1 -1
  43. package/lib/module/theme/LightUIKitTheme.js +2 -1
  44. package/lib/module/theme/LightUIKitTheme.js.map +1 -1
  45. package/lib/module/types.js.map +1 -1
  46. package/lib/module/ui/BottomSheet/index.js +1 -0
  47. package/lib/module/ui/BottomSheet/index.js.map +1 -1
  48. package/lib/module/ui/Dialog/DialogSheet.js +4 -3
  49. package/lib/module/ui/Dialog/DialogSheet.js.map +1 -1
  50. package/lib/module/ui/GroupChannelMessage/Message.file.image.js +2 -2
  51. package/lib/module/ui/GroupChannelMessage/Message.file.image.js.map +1 -1
  52. package/lib/module/ui/GroupChannelMessage/Message.file.js +7 -10
  53. package/lib/module/ui/GroupChannelMessage/Message.file.js.map +1 -1
  54. package/lib/module/ui/GroupChannelMessage/Message.file.video.js +11 -71
  55. package/lib/module/ui/GroupChannelMessage/Message.file.video.js.map +1 -1
  56. package/lib/module/ui/GroupChannelMessage/MessageContainer.js +7 -5
  57. package/lib/module/ui/GroupChannelMessage/MessageContainer.js.map +1 -1
  58. package/lib/module/ui/GroupChannelMessage/MessageOpenGraph.js +2 -2
  59. package/lib/module/ui/GroupChannelMessage/MessageOpenGraph.js.map +1 -1
  60. package/lib/module/ui/GroupChannelMessage/index.js.map +1 -1
  61. package/lib/module/ui/OpenChannelMessage/Message.file.image.js +2 -2
  62. package/lib/module/ui/OpenChannelMessage/Message.file.image.js.map +1 -1
  63. package/lib/module/ui/OpenChannelMessage/Message.file.js +2 -8
  64. package/lib/module/ui/OpenChannelMessage/Message.file.js.map +1 -1
  65. package/lib/module/ui/OpenChannelMessage/Message.file.video.js +12 -77
  66. package/lib/module/ui/OpenChannelMessage/Message.file.video.js.map +1 -1
  67. package/lib/module/ui/OpenChannelMessage/Message.user.og.js +1 -1
  68. package/lib/module/ui/OpenChannelMessage/Message.user.og.js.map +1 -1
  69. package/lib/typescript/src/components/Icon/index.d.ts +5 -0
  70. package/lib/typescript/src/components/VideoThumbnail/index.d.ts +13 -0
  71. package/lib/typescript/src/index.d.ts +1 -0
  72. package/lib/typescript/src/types.d.ts +1 -1
  73. package/lib/typescript/src/ui/BottomSheet/index.d.ts +1 -0
  74. package/lib/typescript/src/ui/Dialog/DialogSheet.d.ts +2 -1
  75. package/lib/typescript/src/ui/GroupChannelMessage/MessageContainer.d.ts +2 -2
  76. package/lib/typescript/src/ui/GroupChannelMessage/MessageOpenGraph.d.ts +1 -1
  77. package/lib/typescript/src/ui/GroupChannelMessage/index.d.ts +8 -0
  78. package/package.json +3 -3
  79. package/src/components/Icon/index.tsx +11 -7
  80. package/src/components/VideoThumbnail/index.tsx +107 -0
  81. package/src/index.ts +1 -0
  82. package/src/theme/DarkUIKitTheme.ts +1 -0
  83. package/src/theme/LightUIKitTheme.ts +1 -0
  84. package/src/types.ts +1 -1
  85. package/src/ui/BottomSheet/index.tsx +2 -0
  86. package/src/ui/Dialog/DialogSheet.tsx +6 -3
  87. package/src/ui/GroupChannelMessage/Message.file.image.tsx +2 -2
  88. package/src/ui/GroupChannelMessage/Message.file.tsx +4 -6
  89. package/src/ui/GroupChannelMessage/Message.file.video.tsx +12 -60
  90. package/src/ui/GroupChannelMessage/MessageContainer.tsx +18 -13
  91. package/src/ui/GroupChannelMessage/MessageOpenGraph.tsx +3 -3
  92. package/src/ui/GroupChannelMessage/index.ts +1 -0
  93. package/src/ui/OpenChannelMessage/Message.file.image.tsx +2 -2
  94. package/src/ui/OpenChannelMessage/Message.file.tsx +1 -3
  95. package/src/ui/OpenChannelMessage/Message.file.video.tsx +12 -55
  96. package/src/ui/OpenChannelMessage/Message.user.og.tsx +1 -1
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ export type { RegexTextPattern } from './components/RegexText';
14
14
  export { default as Switch } from './components/Switch';
15
15
  export { default as Text } from './components/Text';
16
16
  export { default as TextInput } from './components/TextInput';
17
+ export { VideoThumbnail } from './components/VideoThumbnail';
17
18
 
18
19
  /** UI **/
19
20
  export { default as ActionMenu } from './ui/ActionMenu';
@@ -99,6 +99,7 @@ const DarkUIKitTheme = createTheme({
99
99
  message: palette.onBackgroundDark02,
100
100
  highlight: palette.primary200,
101
101
  destructive: palette.error300,
102
+ blurred: palette.onBackgroundDark04,
102
103
  },
103
104
  },
104
105
  },
@@ -99,6 +99,7 @@ const LightUIKitTheme = createTheme({
99
99
  message: palette.onBackgroundLight02,
100
100
  highlight: palette.primary300,
101
101
  destructive: palette.error300,
102
+ blurred: palette.onBackgroundLight04,
102
103
  },
103
104
  },
104
105
  },
package/src/types.ts CHANGED
@@ -93,7 +93,7 @@ export type ComponentColorTree = GetColorTree<{
93
93
  ColorPart: {
94
94
  Header: 'background' | 'borderBottom';
95
95
  Button: 'background' | 'content';
96
- Dialog: 'background' | 'text' | 'message' | 'highlight' | 'destructive';
96
+ Dialog: 'background' | 'text' | 'message' | 'highlight' | 'destructive' | 'blurred';
97
97
  Input: 'text' | 'placeholder' | 'background' | 'highlight';
98
98
  Badge: 'text' | 'background';
99
99
  Placeholder: 'content' | 'highlight';
@@ -14,6 +14,7 @@ export type BottomSheetItem = {
14
14
  iconColor?: string;
15
15
  title: string;
16
16
  titleColor?: string;
17
+ disabled?: boolean;
17
18
  onPress: () => void;
18
19
  }[];
19
20
  HeaderComponent?: (props: HeaderProps) => JSX.Element;
@@ -44,6 +45,7 @@ const BottomSheet = ({ onDismiss, onHide, visible, sheetItems, HeaderComponent }
44
45
  activeOpacity={0.75}
45
46
  key={props.title + idx}
46
47
  style={{ paddingLeft: left, paddingRight: right }}
48
+ disabled={props.disabled}
47
49
  onPress={async () => {
48
50
  await onHide();
49
51
  try {
@@ -23,22 +23,25 @@ export type SheetItemProps = {
23
23
  iconColor?: string;
24
24
  title: string;
25
25
  titleColor?: string;
26
+ disabled?: boolean;
26
27
  };
27
- const SheetItem = ({ icon, title, iconColor, titleColor }: SheetItemProps) => {
28
+ const SheetItem = ({ icon, title, iconColor, titleColor, disabled = false }: SheetItemProps) => {
28
29
  const { colors } = useUIKitTheme();
29
30
  return (
30
31
  <View style={[styles.sheetItemContainer, { backgroundColor: colors.ui.dialog.default.none.background }]}>
31
32
  {icon && (
32
33
  <Icon
33
34
  icon={icon}
34
- color={iconColor ?? colors.ui.dialog.default.none.highlight}
35
+ color={
36
+ iconColor ?? (disabled ? colors.ui.dialog.default.none.blurred : colors.ui.dialog.default.none.highlight)
37
+ }
35
38
  containerStyle={styles.sheetItemIcon}
36
39
  />
37
40
  )}
38
41
  <Text
39
42
  subtitle1
40
43
  numberOfLines={1}
41
- color={titleColor ?? colors.ui.dialog.default.none.text}
44
+ color={titleColor ?? (disabled ? colors.ui.dialog.default.none.blurred : colors.ui.dialog.default.none.text)}
42
45
  style={styles.sheetItemText}
43
46
  >
44
47
  {title}
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  import type { SendbirdFileMessage } from '@sendbird/uikit-utils';
4
- import { getAvailableUriFromFileMessage } from '@sendbird/uikit-utils';
4
+ import { getThumbnailUriFromFileMessage } from '@sendbird/uikit-utils';
5
5
 
6
6
  import Box from '../../components/Box';
7
7
  import ImageWithPlaceholder from '../../components/ImageWithPlaceholder';
@@ -20,7 +20,7 @@ const ImageFileMessage = (props: GroupChannelMessageProps<SendbirdFileMessage>)
20
20
  <MessageContainer {...props}>
21
21
  <Box style={styles.container} backgroundColor={colors.ui.groupChannelMessage[variant].enabled.background}>
22
22
  <PressBox activeOpacity={0.8} onPress={onPress} onLongPress={onLongPress}>
23
- <ImageWithPlaceholder source={{ uri: getAvailableUriFromFileMessage(props.message) }} style={styles.image} />
23
+ <ImageWithPlaceholder source={{ uri: getThumbnailUriFromFileMessage(props.message) }} style={styles.image} />
24
24
  </PressBox>
25
25
  {props.children}
26
26
  </Box>
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
 
3
- import { SendbirdFileMessage, getFileExtension, getFileType } from '@sendbird/uikit-utils';
3
+ import { SendbirdFileMessage, getFileExtension, getFileType, truncate } from '@sendbird/uikit-utils';
4
4
 
5
5
  import Box from '../../components/Box';
6
6
  import Icon from '../../components/Icon';
@@ -11,8 +11,6 @@ import useUIKitTheme from '../../theme/useUIKitTheme';
11
11
  import MessageContainer from './MessageContainer';
12
12
  import type { GroupChannelMessageProps } from './index';
13
13
 
14
- const iconMapper = { audio: 'file-audio', image: 'photo', video: 'play', file: 'file-document' } as const;
15
-
16
14
  type Props = GroupChannelMessageProps<SendbirdFileMessage>;
17
15
 
18
16
  const FileMessage = (props: Props) => {
@@ -28,8 +26,8 @@ const FileMessage = (props: Props) => {
28
26
  {({ pressed }) => (
29
27
  <Box backgroundColor={pressed ? color.pressed.background : color.enabled.background} style={styles.container}>
30
28
  <Box style={styles.bubble}>
31
- <Icon
32
- icon={iconMapper[fileType]}
29
+ <Icon.File
30
+ fileType={fileType}
33
31
  size={24}
34
32
  containerStyle={{ backgroundColor: colors.background, padding: 2, borderRadius: 8, marginRight: 8 }}
35
33
  />
@@ -40,7 +38,7 @@ const FileMessage = (props: Props) => {
40
38
  color={pressed ? color.pressed.textMsg : color.enabled.textMsg}
41
39
  style={styles.name}
42
40
  >
43
- {props.strings?.fileName || props.message.name}
41
+ {truncate(props.strings?.fileName || props.message.name, { mode: 'mid', maxLen: 20 })}
44
42
  </Text>
45
43
  </Box>
46
44
  {props.children}
@@ -1,13 +1,11 @@
1
- import React, { useEffect, useRef, useState } from 'react';
2
- import { StyleSheet } from 'react-native';
1
+ import React from 'react';
3
2
 
4
3
  import type { SendbirdFileMessage } from '@sendbird/uikit-utils';
5
- import { getAvailableUriFromFileMessage } from '@sendbird/uikit-utils';
4
+ import { getThumbnailUriFromFileMessage } from '@sendbird/uikit-utils';
6
5
 
7
6
  import Box from '../../components/Box';
8
- import Icon from '../../components/Icon';
9
- import ImageWithPlaceholder from '../../components/ImageWithPlaceholder';
10
7
  import PressBox from '../../components/PressBox';
8
+ import { VideoThumbnail } from '../../components/VideoThumbnail';
11
9
  import createStyleSheet from '../../styles/createStyleSheet';
12
10
  import useUIKitTheme from '../../theme/useUIKitTheme';
13
11
  import MessageContainer from './MessageContainer';
@@ -15,41 +13,24 @@ import type { GroupChannelMessageProps } from './index';
15
13
 
16
14
  type Props = GroupChannelMessageProps<
17
15
  SendbirdFileMessage,
18
- {
19
- fetchThumbnailFromVideoSource: (uri: string) => Promise<{ path: string } | null>;
20
- }
16
+ { fetchThumbnailFromVideoSource: (uri: string) => Promise<{ path: string } | null> }
21
17
  >;
22
18
 
23
19
  const VideoFileMessage = (props: Props) => {
24
20
  const { onPress, onLongPress, variant = 'incoming' } = props;
25
21
 
26
- const { colors, palette, select } = useUIKitTheme();
27
- const uri = getAvailableUriFromFileMessage(props.message);
28
- const { thumbnail, loading } = useRetry(() => props.fetchThumbnailFromVideoSource(uri));
22
+ const { colors } = useUIKitTheme();
23
+ const uri = getThumbnailUriFromFileMessage(props.message);
29
24
 
30
25
  return (
31
26
  <MessageContainer {...props}>
32
27
  <Box style={styles.container} backgroundColor={colors.ui.groupChannelMessage[variant].enabled.background}>
33
- <PressBox activeOpacity={0.8} onPress={onPress} onLongPress={onLongPress} style={styles.image}>
34
- {loading ? (
35
- <Box
36
- style={StyleSheet.absoluteFill}
37
- backgroundColor={select({ dark: palette.background400, light: palette.background100 })}
38
- />
39
- ) : (
40
- <ImageWithPlaceholder source={{ uri: thumbnail ?? 'invalid-image' }} style={StyleSheet.absoluteFill} />
41
- )}
42
-
43
- {(loading || thumbnail !== null) && (
44
- <Box style={StyleSheet.absoluteFill} alignItems={'center'} justifyContent={'center'}>
45
- <Icon
46
- icon={'play'}
47
- size={28}
48
- color={palette.onBackgroundLight02}
49
- containerStyle={[styles.playIcon, { backgroundColor: palette.onBackgroundDark01 }]}
50
- />
51
- </Box>
52
- )}
28
+ <PressBox activeOpacity={0.8} onPress={onPress} onLongPress={onLongPress}>
29
+ <VideoThumbnail
30
+ style={styles.image}
31
+ source={uri}
32
+ fetchThumbnailFromVideoSource={props.fetchThumbnailFromVideoSource}
33
+ />
53
34
  </PressBox>
54
35
  {props.children}
55
36
  </Box>
@@ -57,35 +38,6 @@ const VideoFileMessage = (props: Props) => {
57
38
  );
58
39
  };
59
40
 
60
- const useRetry = (fetch: () => Promise<{ path: string } | null>, retryCount = 5) => {
61
- const [state, setState] = useState({ thumbnail: null as null | string, loading: true });
62
- const retryCountRef = useRef(0);
63
- const retryTimeoutRef = useRef<NodeJS.Timeout>();
64
- const fetchThumbnail = useRef(fetch);
65
- fetchThumbnail.current = fetch;
66
-
67
- useEffect(() => {
68
- if (!state.thumbnail) {
69
- const reloadReservation = () => {
70
- if (retryCountRef.current < retryCount) {
71
- retryTimeoutRef.current = setTimeout(() => {
72
- retryCountRef.current++;
73
- reloadReservation();
74
- fetchThumbnail.current().then((result) => {
75
- setState({ loading: false, thumbnail: result?.path ?? null });
76
- });
77
- }, retryCountRef.current * 5000);
78
- }
79
- };
80
-
81
- return reloadReservation();
82
- } else {
83
- return clearTimeout(retryTimeoutRef.current);
84
- }
85
- }, [state.thumbnail]);
86
-
87
- return state;
88
- };
89
41
  const styles = createStyleSheet({
90
42
  container: {
91
43
  borderRadius: 16,
@@ -28,6 +28,7 @@ MessageContainer.Incoming = function MessageContainerIncoming({
28
28
  message,
29
29
  onPressAvatar,
30
30
  strings,
31
+ parentMessage,
31
32
  }: Props) {
32
33
  const { colors } = useUIKitTheme();
33
34
  const color = colors.ui.groupChannelMessage.incoming;
@@ -42,7 +43,8 @@ MessageContainer.Incoming = function MessageContainerIncoming({
42
43
  )}
43
44
  </Box>
44
45
  <Box flexShrink={1}>
45
- {!groupedWithPrev && (
46
+ {parentMessage}
47
+ {!groupedWithPrev && !message.parentMessage && (
46
48
  <Box marginLeft={12} marginBottom={4}>
47
49
  {(message.isFileMessage() || message.isUserMessage()) && (
48
50
  <Text caption1 color={color.enabled.textSenderName} numberOfLines={1}>
@@ -73,24 +75,27 @@ MessageContainer.Outgoing = function MessageContainerOutgoing({
73
75
  groupedWithNext,
74
76
  strings,
75
77
  sendingStatus,
78
+ parentMessage,
76
79
  }: Props) {
77
80
  const { colors } = useUIKitTheme();
78
81
  const color = colors.ui.groupChannelMessage.outgoing;
79
82
 
80
83
  return (
81
- <Box flexDirection={'row'} justifyContent={'flex-end'} alignItems={'flex-end'}>
82
- <Box flexDirection={'row'} alignItems={'flex-end'} justifyContent={'center'}>
83
- {sendingStatus && <Box marginRight={4}>{sendingStatus}</Box>}
84
-
85
- {!groupedWithNext && (
86
- <Box marginRight={4}>
87
- <Text caption4 color={color.enabled.textTime}>
88
- {strings?.sentDate ?? getMessageTimeFormat(new Date(message.createdAt))}
89
- </Text>
90
- </Box>
91
- )}
84
+ <Box>
85
+ {parentMessage}
86
+ <Box flexDirection={'row'} justifyContent={'flex-end'} alignItems={'flex-end'}>
87
+ <Box flexDirection={'row'} alignItems={'flex-end'} justifyContent={'center'}>
88
+ {sendingStatus && <Box marginRight={4}>{sendingStatus}</Box>}
89
+ {!groupedWithNext && (
90
+ <Box marginRight={4}>
91
+ <Text caption4 color={color.enabled.textTime}>
92
+ {strings?.sentDate ?? getMessageTimeFormat(new Date(message.createdAt))}
93
+ </Text>
94
+ </Box>
95
+ )}
96
+ </Box>
97
+ <Box style={styles.bubble}>{children}</Box>
92
98
  </Box>
93
- <Box style={styles.bubble}>{children}</Box>
94
99
  </Box>
95
100
  );
96
101
  };
@@ -15,7 +15,7 @@ const MessageOpenGraph = ({
15
15
  ogMetaData,
16
16
  variant,
17
17
  }: {
18
- ogMetaData: Required<SendbirdUserMessage>['ogMetaData'];
18
+ ogMetaData: NonNullable<SendbirdUserMessage['ogMetaData']>;
19
19
  variant: 'outgoing' | 'incoming';
20
20
  onPressURL?: (url: string) => void;
21
21
  onLongPress?: () => void;
@@ -31,7 +31,7 @@ const MessageOpenGraph = ({
31
31
  >
32
32
  {({ pressed }) => (
33
33
  <Box backgroundColor={pressed ? color.pressed.background : color.enabled.background}>
34
- {Boolean(ogMetaData.defaultImage) && (
34
+ {!!ogMetaData.defaultImage && (
35
35
  <ImageWithPlaceholder style={styles.ogImage} source={{ uri: ogMetaData.defaultImage.url }} />
36
36
  )}
37
37
 
@@ -42,7 +42,7 @@ const MessageOpenGraph = ({
42
42
  <Text numberOfLines={3} body2 color={colors.onBackground01} style={styles.ogTitle}>
43
43
  {ogMetaData.title}
44
44
  </Text>
45
- {Boolean(ogMetaData.description) && (
45
+ {!!ogMetaData.description && (
46
46
  <Text numberOfLines={1} caption2 color={colors.onBackground01} style={styles.ogDesc}>
47
47
  {ogMetaData.description}
48
48
  </Text>
@@ -25,6 +25,7 @@ export type GroupChannelMessageProps<T extends SendbirdMessage, AdditionalProps
25
25
 
26
26
  children?: React.ReactNode;
27
27
  sendingStatus?: React.ReactNode;
28
+ parentMessage?: React.ReactNode;
28
29
 
29
30
  groupedWithPrev: boolean;
30
31
  groupedWithNext: boolean;
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  import type { SendbirdFileMessage } from '@sendbird/uikit-utils';
4
- import { getAvailableUriFromFileMessage } from '@sendbird/uikit-utils';
4
+ import { getThumbnailUriFromFileMessage } from '@sendbird/uikit-utils';
5
5
 
6
6
  import Box from '../../components/Box';
7
7
  import ImageWithPlaceholder from '../../components/ImageWithPlaceholder';
@@ -12,7 +12,7 @@ import type { OpenChannelMessageProps } from './index';
12
12
 
13
13
  const ImageFileMessage = (props: OpenChannelMessageProps<SendbirdFileMessage>) => {
14
14
  const { onPress, onLongPress, ...rest } = props;
15
- const uri = getAvailableUriFromFileMessage(props.message);
15
+ const uri = getThumbnailUriFromFileMessage(props.message);
16
16
  return (
17
17
  <MessageContainer {...rest}>
18
18
  <Box borderRadius={8} overflow={'hidden'} style={styles.container}>
@@ -11,8 +11,6 @@ import useUIKitTheme from '../../theme/useUIKitTheme';
11
11
  import MessageContainer from './MessageContainer';
12
12
  import type { OpenChannelMessageProps } from './index';
13
13
 
14
- const iconMapper = { audio: 'file-audio', image: 'photo', video: 'play', file: 'file-document' } as const;
15
-
16
14
  type Props = {};
17
15
  const FileMessage = (props: OpenChannelMessageProps<SendbirdFileMessage, Props>) => {
18
16
  const { colors } = useUIKitTheme();
@@ -40,7 +38,7 @@ const FileMessage = (props: OpenChannelMessageProps<SendbirdFileMessage, Props>)
40
38
  alignItems={'flex-start'}
41
39
  backgroundColor={colors.background}
42
40
  >
43
- <Icon icon={iconMapper[type]} size={32} />
41
+ <Icon.File fileType={type} size={32} />
44
42
  </Box>
45
43
  <Text
46
44
  body3
@@ -1,84 +1,41 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React from 'react';
2
2
 
3
3
  import type { SendbirdFileMessage } from '@sendbird/uikit-utils';
4
- import { getAvailableUriFromFileMessage } from '@sendbird/uikit-utils';
4
+ import { getThumbnailUriFromFileMessage } from '@sendbird/uikit-utils';
5
5
 
6
- import Box from '../../components/Box';
7
- import Icon from '../../components/Icon';
8
- import ImageWithPlaceholder from '../../components/ImageWithPlaceholder';
9
6
  import PressBox from '../../components/PressBox';
7
+ import { VideoThumbnail } from '../../components/VideoThumbnail';
10
8
  import createStyleSheet from '../../styles/createStyleSheet';
11
- import useUIKitTheme from '../../theme/useUIKitTheme';
12
9
  import MessageContainer from './MessageContainer';
13
10
  import type { OpenChannelMessageProps } from './index';
14
11
 
15
12
  type Props = {
16
13
  fetchThumbnailFromVideoSource: (uri: string) => Promise<{ path: string } | null>;
17
14
  };
15
+
18
16
  const VideoFileMessage = (props: OpenChannelMessageProps<SendbirdFileMessage, Props>) => {
19
- const { colors, palette } = useUIKitTheme();
20
17
  const { onPress, onLongPress, ...rest } = props;
21
- const uri = getAvailableUriFromFileMessage(props.message);
22
- const { thumbnail, loading } = useRetry(() => props.fetchThumbnailFromVideoSource(uri));
18
+ const uri = getThumbnailUriFromFileMessage(props.message);
23
19
 
24
20
  return (
25
21
  <MessageContainer {...rest}>
26
22
  <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>
23
+ <VideoThumbnail
24
+ style={styles.container}
25
+ source={uri}
26
+ fetchThumbnailFromVideoSource={props.fetchThumbnailFromVideoSource}
27
+ />
45
28
  </PressBox>
46
29
  </MessageContainer>
47
30
  );
48
31
  };
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
32
 
70
- return reloadReservation();
71
- } else {
72
- return clearTimeout(retryTimeoutRef.current);
73
- }
74
- }, [state.thumbnail]);
75
-
76
- return state;
77
- };
78
33
  const styles = createStyleSheet({
79
34
  container: {
80
35
  maxWidth: 296,
81
36
  height: 196,
37
+ borderRadius: 8,
38
+ overflow: 'hidden',
82
39
  },
83
40
  iconContainer: {
84
41
  position: 'absolute',
@@ -88,7 +88,7 @@ const OpenGraphUserMessage = (props: OpenChannelMessageProps<SendbirdUserMessage
88
88
  </Text>
89
89
  )}
90
90
 
91
- {Boolean(props.message.ogMetaData.defaultImage) && (
91
+ {!!props.message.ogMetaData.defaultImage && (
92
92
  <ImageWithPlaceholder
93
93
  style={styles.ogImage}
94
94
  source={{ uri: props.message.ogMetaData.defaultImage.url }}