@sendbird/uikit-react-native 1.1.0 → 1.1.2

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 (144) hide show
  1. package/lib/commonjs/components/FileViewer.js +11 -13
  2. package/lib/commonjs/components/FileViewer.js.map +1 -1
  3. package/lib/commonjs/components/MessageRenderer/FileMessage/ImageFileMessage.js +47 -15
  4. package/lib/commonjs/components/MessageRenderer/FileMessage/ImageFileMessage.js.map +1 -1
  5. package/lib/commonjs/components/MessageRenderer/FileMessage/VideoFileMessage.js +51 -34
  6. package/lib/commonjs/components/MessageRenderer/FileMessage/VideoFileMessage.js.map +1 -1
  7. package/lib/commonjs/components/MessageRenderer/MessageIncomingSenderName.js +2 -1
  8. package/lib/commonjs/components/MessageRenderer/MessageIncomingSenderName.js.map +1 -1
  9. package/lib/commonjs/components/MessageRenderer/MessageOutgoingStatus.js +20 -56
  10. package/lib/commonjs/components/MessageRenderer/MessageOutgoingStatus.js.map +1 -1
  11. package/lib/commonjs/components/MessageRenderer/index.js +7 -2
  12. package/lib/commonjs/components/MessageRenderer/index.js.map +1 -1
  13. package/lib/commonjs/{components → containers}/GroupChannelPreviewContainer.js +30 -53
  14. package/lib/commonjs/containers/GroupChannelPreviewContainer.js.map +1 -0
  15. package/lib/commonjs/{InternalErrorBoundary.js → containers/InternalErrorBoundaryContainer.js} +5 -5
  16. package/lib/commonjs/containers/InternalErrorBoundaryContainer.js.map +1 -0
  17. package/lib/commonjs/{SendbirdUIKitContainer.js → containers/SendbirdUIKitContainer.js} +10 -10
  18. package/lib/commonjs/containers/SendbirdUIKitContainer.js.map +1 -0
  19. package/lib/commonjs/domain/groupChannel/component/GroupChannelInput/SendInput.js +39 -6
  20. package/lib/commonjs/domain/groupChannel/component/GroupChannelInput/SendInput.js.map +1 -1
  21. package/lib/commonjs/domain/groupChannelList/types.js.map +1 -1
  22. package/lib/commonjs/domain/groupChannelSettings/component/GroupChannelSettingsInfo.js +1 -1
  23. package/lib/commonjs/domain/groupChannelSettings/component/GroupChannelSettingsInfo.js.map +1 -1
  24. package/lib/commonjs/domain/groupChannelSettings/module/moduleContext.js +35 -2
  25. package/lib/commonjs/domain/groupChannelSettings/module/moduleContext.js.map +1 -1
  26. package/lib/commonjs/fragments/createGroupChannelFragment.js +1 -1
  27. package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
  28. package/lib/commonjs/fragments/createGroupChannelListFragment.js +6 -6
  29. package/lib/commonjs/fragments/createGroupChannelListFragment.js.map +1 -1
  30. package/lib/commonjs/index.js +1 -1
  31. package/lib/commonjs/index.js.map +1 -1
  32. package/lib/commonjs/{InternalLocalCacheStorage.js → libs/InternalLocalCacheStorage.js} +0 -0
  33. package/lib/commonjs/libs/InternalLocalCacheStorage.js.map +1 -0
  34. package/lib/commonjs/libs/SBUError.js +41 -0
  35. package/lib/commonjs/libs/SBUError.js.map +1 -0
  36. package/lib/commonjs/libs/SBUUtils.js +20 -0
  37. package/lib/commonjs/libs/SBUUtils.js.map +1 -0
  38. package/lib/commonjs/localization/StringSet.type.js +6 -0
  39. package/lib/commonjs/localization/StringSet.type.js.map +1 -1
  40. package/lib/commonjs/platform/createFileService.expo.js +6 -4
  41. package/lib/commonjs/platform/createFileService.expo.js.map +1 -1
  42. package/lib/commonjs/platform/createFileService.native.js +20 -8
  43. package/lib/commonjs/platform/createFileService.native.js.map +1 -1
  44. package/lib/commonjs/platform/types.js +4 -0
  45. package/lib/commonjs/platform/types.js.map +1 -1
  46. package/lib/commonjs/version.js +1 -1
  47. package/lib/commonjs/version.js.map +1 -1
  48. package/lib/module/components/FileViewer.js +13 -12
  49. package/lib/module/components/FileViewer.js.map +1 -1
  50. package/lib/module/components/MessageRenderer/FileMessage/ImageFileMessage.js +48 -17
  51. package/lib/module/components/MessageRenderer/FileMessage/ImageFileMessage.js.map +1 -1
  52. package/lib/module/components/MessageRenderer/FileMessage/VideoFileMessage.js +52 -35
  53. package/lib/module/components/MessageRenderer/FileMessage/VideoFileMessage.js.map +1 -1
  54. package/lib/module/components/MessageRenderer/MessageIncomingSenderName.js +2 -1
  55. package/lib/module/components/MessageRenderer/MessageIncomingSenderName.js.map +1 -1
  56. package/lib/module/components/MessageRenderer/MessageOutgoingStatus.js +17 -51
  57. package/lib/module/components/MessageRenderer/MessageOutgoingStatus.js.map +1 -1
  58. package/lib/module/components/MessageRenderer/index.js +7 -2
  59. package/lib/module/components/MessageRenderer/index.js.map +1 -1
  60. package/lib/module/{components → containers}/GroupChannelPreviewContainer.js +28 -51
  61. package/lib/module/containers/GroupChannelPreviewContainer.js.map +1 -0
  62. package/lib/module/{InternalErrorBoundary.js → containers/InternalErrorBoundaryContainer.js} +5 -5
  63. package/lib/module/containers/InternalErrorBoundaryContainer.js.map +1 -0
  64. package/lib/module/{SendbirdUIKitContainer.js → containers/SendbirdUIKitContainer.js} +10 -10
  65. package/lib/module/containers/SendbirdUIKitContainer.js.map +1 -0
  66. package/lib/module/domain/groupChannel/component/GroupChannelInput/SendInput.js +38 -7
  67. package/lib/module/domain/groupChannel/component/GroupChannelInput/SendInput.js.map +1 -1
  68. package/lib/module/domain/groupChannelList/types.js.map +1 -1
  69. package/lib/module/domain/groupChannelSettings/component/GroupChannelSettingsInfo.js +1 -1
  70. package/lib/module/domain/groupChannelSettings/component/GroupChannelSettingsInfo.js.map +1 -1
  71. package/lib/module/domain/groupChannelSettings/module/moduleContext.js +34 -3
  72. package/lib/module/domain/groupChannelSettings/module/moduleContext.js.map +1 -1
  73. package/lib/module/fragments/createGroupChannelFragment.js +1 -1
  74. package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
  75. package/lib/module/fragments/createGroupChannelListFragment.js +6 -6
  76. package/lib/module/fragments/createGroupChannelListFragment.js.map +1 -1
  77. package/lib/module/index.js +1 -1
  78. package/lib/module/index.js.map +1 -1
  79. package/lib/module/{InternalLocalCacheStorage.js → libs/InternalLocalCacheStorage.js} +0 -0
  80. package/lib/module/libs/InternalLocalCacheStorage.js.map +1 -0
  81. package/lib/module/libs/SBUError.js +32 -0
  82. package/lib/module/libs/SBUError.js.map +1 -0
  83. package/lib/module/libs/SBUUtils.js +10 -0
  84. package/lib/module/libs/SBUUtils.js.map +1 -0
  85. package/lib/module/localization/StringSet.type.js +6 -0
  86. package/lib/module/localization/StringSet.type.js.map +1 -1
  87. package/lib/module/platform/createFileService.expo.js +5 -4
  88. package/lib/module/platform/createFileService.expo.js.map +1 -1
  89. package/lib/module/platform/createFileService.native.js +18 -8
  90. package/lib/module/platform/createFileService.native.js.map +1 -1
  91. package/lib/module/platform/types.js +1 -1
  92. package/lib/module/platform/types.js.map +1 -1
  93. package/lib/module/version.js +1 -1
  94. package/lib/module/version.js.map +1 -1
  95. package/lib/typescript/src/{components → containers}/GroupChannelPreviewContainer.d.ts +0 -0
  96. package/lib/typescript/src/{InternalErrorBoundary.d.ts → containers/InternalErrorBoundaryContainer.d.ts} +3 -3
  97. package/lib/typescript/src/{SendbirdUIKitContainer.d.ts → containers/SendbirdUIKitContainer.d.ts} +4 -4
  98. package/lib/typescript/src/domain/groupChannelList/types.d.ts +2 -2
  99. package/lib/typescript/src/index.d.ts +1 -1
  100. package/lib/typescript/src/{InternalLocalCacheStorage.d.ts → libs/InternalLocalCacheStorage.d.ts} +2 -2
  101. package/lib/typescript/src/libs/SBUError.d.ts +14 -0
  102. package/lib/typescript/src/libs/SBUUtils.d.ts +3 -0
  103. package/lib/typescript/src/localization/StringSet.type.d.ts +3 -0
  104. package/lib/typescript/src/platform/types.d.ts +2 -1
  105. package/lib/typescript/src/version.d.ts +1 -1
  106. package/package.json +5 -5
  107. package/src/components/FileViewer.tsx +19 -12
  108. package/src/components/MessageRenderer/FileMessage/ImageFileMessage.tsx +55 -12
  109. package/src/components/MessageRenderer/FileMessage/VideoFileMessage.tsx +38 -30
  110. package/src/components/MessageRenderer/MessageIncomingSenderName.tsx +1 -1
  111. package/src/components/MessageRenderer/MessageOutgoingStatus.tsx +13 -46
  112. package/src/components/MessageRenderer/index.tsx +5 -2
  113. package/src/{components → containers}/GroupChannelPreviewContainer.tsx +20 -37
  114. package/src/{InternalErrorBoundary.tsx → containers/InternalErrorBoundaryContainer.tsx} +4 -4
  115. package/src/{SendbirdUIKitContainer.tsx → containers/SendbirdUIKitContainer.tsx} +13 -13
  116. package/src/domain/groupChannel/component/GroupChannelInput/SendInput.tsx +28 -4
  117. package/src/domain/groupChannelList/types.ts +2 -2
  118. package/src/domain/groupChannelSettings/component/GroupChannelSettingsInfo.tsx +1 -1
  119. package/src/domain/groupChannelSettings/module/moduleContext.tsx +26 -3
  120. package/src/fragments/createGroupChannelFragment.tsx +1 -1
  121. package/src/fragments/createGroupChannelListFragment.tsx +6 -6
  122. package/src/index.ts +1 -1
  123. package/src/{InternalLocalCacheStorage.ts → libs/InternalLocalCacheStorage.ts} +1 -1
  124. package/src/libs/SBUError.ts +26 -0
  125. package/src/libs/SBUUtils.ts +9 -0
  126. package/src/localization/StringSet.type.ts +10 -0
  127. package/src/platform/createFileService.expo.ts +5 -4
  128. package/src/platform/createFileService.native.ts +17 -8
  129. package/src/platform/types.ts +3 -1
  130. package/src/version.ts +1 -1
  131. package/lib/commonjs/InternalErrorBoundary.js.map +0 -1
  132. package/lib/commonjs/InternalLocalCacheStorage.js.map +0 -1
  133. package/lib/commonjs/SendbirdUIKitContainer.js.map +0 -1
  134. package/lib/commonjs/components/GroupChannelPreviewContainer.js.map +0 -1
  135. package/lib/commonjs/components/SBUPressable.js +0 -45
  136. package/lib/commonjs/components/SBUPressable.js.map +0 -1
  137. package/lib/module/InternalErrorBoundary.js.map +0 -1
  138. package/lib/module/InternalLocalCacheStorage.js.map +0 -1
  139. package/lib/module/SendbirdUIKitContainer.js.map +0 -1
  140. package/lib/module/components/GroupChannelPreviewContainer.js.map +0 -1
  141. package/lib/module/components/SBUPressable.js +0 -33
  142. package/lib/module/components/SBUPressable.js.map +0 -1
  143. package/lib/typescript/src/components/SBUPressable.d.ts +0 -18
  144. package/src/components/SBUPressable.tsx +0 -40
@@ -1,2 +1,2 @@
1
- declare const VERSION = "1.1.0";
1
+ declare const VERSION = "1.1.2";
2
2
  export default VERSION;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendbird/uikit-react-native",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "react-native-uikit",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -41,9 +41,9 @@
41
41
  "access": "public"
42
42
  },
43
43
  "dependencies": {
44
- "@sendbird/uikit-chat-hooks": "1.1.0",
45
- "@sendbird/uikit-react-native-foundation": "1.1.0",
46
- "@sendbird/uikit-utils": "1.1.0"
44
+ "@sendbird/uikit-chat-hooks": "1.1.2",
45
+ "@sendbird/uikit-react-native-foundation": "1.1.2",
46
+ "@sendbird/uikit-utils": "1.1.2"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@react-native-clipboard/clipboard": "^1.8.5",
@@ -159,5 +159,5 @@
159
159
  "readmeFile": "./README.md",
160
160
  "displayName": "@sendbird/uikit-react-native"
161
161
  },
162
- "gitHead": "787ef6d52fec5d01e9b831d7a6f17e33614e2d09"
162
+ "gitHead": "3bfe51786e73bedc419116e447b79d6b57f9178c"
163
163
  }
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import { StatusBar, StyleSheet, View } from 'react-native';
2
+ import { StatusBar, StyleSheet, TouchableOpacity, View } from 'react-native';
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
4
 
5
5
  import {
@@ -14,10 +14,17 @@ import {
14
14
  useUIKitTheme,
15
15
  } from '@sendbird/uikit-react-native-foundation';
16
16
  import type { SendbirdFileMessage } from '@sendbird/uikit-utils';
17
- import { Logger, getFileExtension, getFileType, isMyMessage, toMegabyte, useIIFE } from '@sendbird/uikit-utils';
17
+ import {
18
+ Logger,
19
+ getFileExtension,
20
+ getFileType,
21
+ isMyMessage,
22
+ toMegabyte,
23
+ truncate,
24
+ useIIFE,
25
+ } from '@sendbird/uikit-utils';
18
26
 
19
27
  import { useLocalization, usePlatformService, useSendbirdChat } from '../hooks/useContext';
20
- import SBUPressable from './SBUPressable';
21
28
 
22
29
  type Props = {
23
30
  fileMessage: SendbirdFileMessage;
@@ -191,14 +198,14 @@ const FileViewerHeader = ({ topInset, onClose, subtitle, title }: HeaderProps) =
191
198
  { paddingTop: topInset, height: defaultHeight + topInset, backgroundColor: palette.overlay01 },
192
199
  ]}
193
200
  >
194
- <SBUPressable as={'TouchableOpacity'} onPress={onClose} style={styles.barButton}>
201
+ <TouchableOpacity onPress={onClose} style={styles.barButton}>
195
202
  <Icon icon={'close'} size={24} color={palette.onBackgroundDark01} />
196
- </SBUPressable>
203
+ </TouchableOpacity>
197
204
  <View style={styles.barTitleContainer}>
198
- <Text h2 color={palette.onBackgroundDark01} style={styles.headerTitle}>
199
- {title}
205
+ <Text h2 color={palette.onBackgroundDark01} style={styles.headerTitle} numberOfLines={1}>
206
+ {truncate(title, { mode: 'mid', maxLen: 18 })}
200
207
  </Text>
201
- <Text caption2 color={palette.onBackgroundDark01}>
208
+ <Text caption2 color={palette.onBackgroundDark01} numberOfLines={1}>
202
209
  {subtitle}
203
210
  </Text>
204
211
  </View>
@@ -233,13 +240,13 @@ const FileViewerFooter = ({ bottomInset, deleteShown, onPressDelete, onPressDown
233
240
  },
234
241
  ]}
235
242
  >
236
- <SBUPressable as={'TouchableOpacity'} onPress={onPressDownload} style={styles.barButton}>
243
+ <TouchableOpacity onPress={onPressDownload} style={styles.barButton}>
237
244
  <Icon icon={'download'} size={24} color={palette.onBackgroundDark01} />
238
- </SBUPressable>
245
+ </TouchableOpacity>
239
246
  <View style={styles.barTitleContainer} />
240
- <SBUPressable as={'TouchableOpacity'} onPress={onPressDelete} style={styles.barButton} disabled={!deleteShown}>
247
+ <TouchableOpacity onPress={onPressDelete} style={styles.barButton} disabled={!deleteShown}>
241
248
  {deleteShown && <Icon icon={'delete'} size={24} color={palette.onBackgroundDark01} />}
242
- </SBUPressable>
249
+ </TouchableOpacity>
243
250
  </View>
244
251
  );
245
252
  };
@@ -1,10 +1,39 @@
1
- import React, { useState } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { Platform, StyleSheet, View } from 'react-native';
2
3
 
3
4
  import { Icon, Image, createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
4
- import { getAvailableUriFromFileMessage } from '@sendbird/uikit-utils';
5
+ import { getAvailableUriFromFileMessage, useForceUpdate } from '@sendbird/uikit-utils';
5
6
 
6
7
  import type { FileMessageProps } from './index';
7
8
 
9
+ const useRetry = (hasError: boolean, retryCount = 5) => {
10
+ if (Platform.OS === 'android') return '';
11
+
12
+ const forceUpdate = useForceUpdate();
13
+ const retryCountRef = useRef(1);
14
+ const retryTimeoutRef = useRef<NodeJS.Timeout>();
15
+
16
+ useEffect(() => {
17
+ if (hasError) {
18
+ const reloadReservation = () => {
19
+ if (retryCountRef.current < retryCount) {
20
+ retryTimeoutRef.current = setTimeout(() => {
21
+ retryCountRef.current++;
22
+ reloadReservation();
23
+ forceUpdate();
24
+ }, retryCountRef.current * 5000);
25
+ }
26
+ };
27
+
28
+ return reloadReservation();
29
+ } else {
30
+ return clearTimeout(retryTimeoutRef.current);
31
+ }
32
+ }, [hasError]);
33
+
34
+ return retryCountRef.current;
35
+ };
36
+
8
37
  const ImageFileMessage = ({ message }: FileMessageProps) => {
9
38
  const { colors } = useUIKitTheme();
10
39
  const [imageNotFound, setImageNotFound] = useState(false);
@@ -12,18 +41,28 @@ const ImageFileMessage = ({ message }: FileMessageProps) => {
12
41
  const fileUrl = getAvailableUriFromFileMessage(message);
13
42
  const style = [styles.image, { backgroundColor: colors.onBackground04 }];
14
43
 
15
- if (imageNotFound) {
16
- return <Icon containerStyle={style} icon={'thumbnail-none'} size={48} color={colors.onBackground02} />;
17
- }
44
+ const key = useRetry(imageNotFound);
18
45
 
19
46
  return (
20
- <Image
21
- source={{ uri: fileUrl }}
22
- style={style}
23
- resizeMode={'cover'}
24
- resizeMethod={'resize'}
25
- onError={() => setImageNotFound(true)}
26
- />
47
+ <View style={style}>
48
+ <Image
49
+ key={key}
50
+ source={{ uri: fileUrl }}
51
+ style={[StyleSheet.absoluteFill, imageNotFound && styles.hide]}
52
+ resizeMode={'cover'}
53
+ resizeMethod={'resize'}
54
+ onError={() => setImageNotFound(true)}
55
+ onLoad={() => setImageNotFound(false)}
56
+ />
57
+ {imageNotFound && (
58
+ <Icon
59
+ containerStyle={StyleSheet.absoluteFill}
60
+ icon={'thumbnail-none'}
61
+ size={48}
62
+ color={colors.onBackground02}
63
+ />
64
+ )}
65
+ </View>
27
66
  );
28
67
  };
29
68
 
@@ -33,6 +72,10 @@ const styles = createStyleSheet({
33
72
  maxWidth: 240,
34
73
  height: 160,
35
74
  borderRadius: 16,
75
+ overflow: 'hidden',
76
+ },
77
+ hide: {
78
+ display: 'none',
36
79
  },
37
80
  });
38
81
 
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
2
  import { View } from 'react-native';
3
3
 
4
4
  import { Icon, Image, createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
@@ -7,35 +7,49 @@ import { getAvailableUriFromFileMessage } from '@sendbird/uikit-utils';
7
7
  import { usePlatformService } from '../../../hooks/useContext';
8
8
  import type { FileMessageProps } from './index';
9
9
 
10
- const VideoFileMessage = ({ message }: FileMessageProps) => {
11
- const { colors } = useUIKitTheme();
10
+ const useRetry = (videoFileUrl: string, retryCount = 5) => {
11
+ const [state, setState] = useState({ thumbnail: null as null | string, loading: true });
12
+ const retryCountRef = useRef(0);
13
+ const retryTimeoutRef = useRef<NodeJS.Timeout>();
12
14
 
13
15
  const { mediaService } = usePlatformService();
14
- const fileUrl = getAvailableUriFromFileMessage(message);
15
- const style = [styles.image, { backgroundColor: colors.onBackground04 }];
16
16
 
17
- const [state, setState] = useState({
18
- thumbnail: null as null | string,
19
- loading: true,
20
- imageNotFound: false,
21
- });
17
+ const fetchThumbnail = () => {
18
+ return mediaService?.getVideoThumbnail({ url: videoFileUrl, timeMills: 1000 }).then((result) => {
19
+ setState({ loading: false, thumbnail: result?.path ?? null });
20
+ });
21
+ };
22
22
 
23
23
  useEffect(() => {
24
- mediaService
25
- ?.getVideoThumbnail({ url: fileUrl, timeMills: 1000 })
26
- .then((result) => {
27
- if (result?.path) {
28
- setState((prev) => ({ ...prev, loading: false, thumbnail: result.path }));
29
- } else {
30
- throw new Error('Cannot generate thumbnail');
24
+ if (!state.thumbnail) {
25
+ const reloadReservation = () => {
26
+ if (retryCountRef.current < retryCount) {
27
+ retryTimeoutRef.current = setTimeout(() => {
28
+ retryCountRef.current++;
29
+ reloadReservation();
30
+ fetchThumbnail();
31
+ }, retryCountRef.current * 5000);
31
32
  }
32
- })
33
- .catch(() => {
34
- setState((prev) => ({ ...prev, loading: false, imageNotFound: true }));
35
- });
36
- }, []);
33
+ };
34
+
35
+ return reloadReservation();
36
+ } else {
37
+ return clearTimeout(retryTimeoutRef.current);
38
+ }
39
+ }, [state.thumbnail]);
40
+
41
+ return state;
42
+ };
43
+
44
+ const VideoFileMessage = ({ message }: FileMessageProps) => {
45
+ const { colors } = useUIKitTheme();
46
+
47
+ const fileUrl = getAvailableUriFromFileMessage(message);
48
+ const style = [styles.image, { backgroundColor: colors.onBackground04 }];
49
+
50
+ const { loading, thumbnail } = useRetry(fileUrl);
37
51
 
38
- if (state.loading || state.imageNotFound) {
52
+ if (loading) {
39
53
  return (
40
54
  <View style={[style, styles.container]}>
41
55
  <PlayIcon />
@@ -45,13 +59,7 @@ const VideoFileMessage = ({ message }: FileMessageProps) => {
45
59
 
46
60
  return (
47
61
  <View style={styles.container}>
48
- <Image
49
- source={{ uri: state.thumbnail || fileUrl }}
50
- style={style}
51
- resizeMode={'cover'}
52
- resizeMethod={'resize'}
53
- onError={() => setState((prev) => ({ ...prev, imageNotFound: true }))}
54
- />
62
+ <Image source={{ uri: thumbnail || fileUrl }} style={style} resizeMode={'cover'} resizeMethod={'resize'} />
55
63
  <PlayIcon />
56
64
  </View>
57
65
  );
@@ -18,7 +18,7 @@ const MessageIncomingSenderName = ({ message, grouping }: Props) => {
18
18
  return (
19
19
  <View style={styles.sender}>
20
20
  {(message.isFileMessage() || message.isUserMessage()) && (
21
- <Text caption1 color={colors.ui.message.incoming.enabled.textSenderName}>
21
+ <Text caption1 color={colors.ui.message.incoming.enabled.textSenderName} numberOfLines={1}>
22
22
  {message.sender?.nickname || STRINGS.LABELS.USER_NO_NAME}
23
23
  </Text>
24
24
  )}
@@ -1,8 +1,8 @@
1
- import React, { useEffect } from 'react';
1
+ import React from 'react';
2
2
 
3
+ import { useMessageOutgoingStatus } from '@sendbird/uikit-chat-hooks';
3
4
  import { Icon, LoadingSpinner, createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
4
5
  import type { SendbirdGroupChannel, SendbirdMessage } from '@sendbird/uikit-utils';
5
- import { isDifferentChannel, useForceUpdate, useUniqId } from '@sendbird/uikit-utils';
6
6
 
7
7
  import { useSendbirdChat } from '../../hooks/useContext';
8
8
 
@@ -12,64 +12,31 @@ type Props = { channel: SendbirdGroupChannel; message: SendbirdMessage };
12
12
  const MessageOutgoingStatus = ({ channel, message }: Props) => {
13
13
  if (!message.isUserMessage() && !message.isFileMessage()) return null;
14
14
 
15
- const { sdk, features } = useSendbirdChat();
15
+ const { sdk } = useSendbirdChat();
16
16
  const { colors } = useUIKitTheme();
17
+ const outgoingStatus = useMessageOutgoingStatus(sdk, channel, message);
17
18
 
18
- const uniqId = useUniqId('MessageOutgoingStatus');
19
- const forceUpdate = useForceUpdate();
20
-
21
- useEffect(() => {
22
- const handlerId = `MessageOutgoingStatus_${uniqId}`;
23
-
24
- if (
25
- message.sendingStatus === 'succeeded' &&
26
- channel.getUnreadMemberCount(message) === 0 &&
27
- channel.getUndeliveredMemberCount(message) === 0
28
- ) {
29
- sdk.removeChannelHandler(handlerId);
30
- } else {
31
- const handler = new sdk.ChannelHandler();
32
-
33
- handler.onReadReceiptUpdated = (eventChannel) => {
34
- if (isDifferentChannel(channel, eventChannel)) return;
35
- forceUpdate();
36
- };
37
-
38
- if (features.deliveryReceiptEnabled) {
39
- handler.onDeliveryReceiptUpdated = (eventChannel) => {
40
- if (isDifferentChannel(channel, eventChannel)) return;
41
- forceUpdate();
42
- };
43
- }
44
-
45
- sdk.addChannelHandler(handlerId, handler);
46
- }
47
-
48
- return () => {
49
- sdk.removeChannelHandler(handlerId);
50
- };
51
- }, [message.sendingStatus]);
52
-
53
- if (message.sendingStatus === 'pending') {
19
+ if (outgoingStatus === 'PENDING') {
54
20
  return <LoadingSpinner size={SIZE} style={styles.container} />;
55
21
  }
56
22
 
57
- if (message.sendingStatus === 'failed') {
23
+ if (outgoingStatus === 'FAILED') {
58
24
  return <Icon icon={'error'} size={SIZE} color={colors.error} style={styles.container} />;
59
25
  }
60
26
 
61
- if (channel.getUnreadMemberCount(message) === 0) {
27
+ if (outgoingStatus === 'READ') {
62
28
  return <Icon icon={'done-all'} size={SIZE} color={colors.secondary} style={styles.container} />;
63
29
  }
64
30
 
65
- if (features.deliveryReceiptEnabled) {
66
- if (channel.getUndeliveredMemberCount(message) === 0) {
67
- return <Icon icon={'done-all'} size={SIZE} color={colors.onBackground03} style={styles.container} />;
68
- }
31
+ if (outgoingStatus === 'UNREAD' || outgoingStatus === 'DELIVERED') {
32
+ return <Icon icon={'done-all'} size={SIZE} color={colors.onBackground03} style={styles.container} />;
33
+ }
34
+
35
+ if (outgoingStatus === 'UNDELIVERED') {
69
36
  return <Icon icon={'done'} size={SIZE} color={colors.onBackground03} style={styles.container} />;
70
37
  }
71
38
 
72
- return <Icon icon={'done-all'} size={SIZE} color={colors.onBackground03} style={styles.container} />;
39
+ return null;
73
40
  };
74
41
 
75
42
  const styles = createStyleSheet({
@@ -107,9 +107,9 @@ const MessageRenderer: GroupChannelProps['Fragment']['renderMessage'] = ({
107
107
  </View>
108
108
  )}
109
109
  {isIncoming && <MessageIncomingAvatar message={message} grouping={groupWithNext} />}
110
- <View>
110
+ <View style={styles.bubbleContainer}>
111
111
  {isIncoming && <MessageIncomingSenderName message={message} grouping={groupWithPrev} />}
112
- <View style={styles.bubbleContainer}>
112
+ <View style={styles.bubbleWrapper}>
113
113
  {messageComponent}
114
114
  {isIncoming && <MessageTime message={message} grouping={groupWithNext} style={styles.timeIncoming} />}
115
115
  </View>
@@ -150,6 +150,9 @@ const styles = createStyleSheet({
150
150
  maxWidth: 240,
151
151
  },
152
152
  bubbleContainer: {
153
+ flexShrink: 1,
154
+ },
155
+ bubbleWrapper: {
153
156
  flexDirection: 'row',
154
157
  alignItems: 'flex-end',
155
158
  },
@@ -1,13 +1,14 @@
1
1
  import React, { useState } from 'react';
2
+ import { Pressable } from 'react-native';
2
3
 
3
- import { useChannelHandler } from '@sendbird/uikit-chat-hooks';
4
+ import { useChannelHandler, useMessageOutgoingStatus } from '@sendbird/uikit-chat-hooks';
4
5
  import {
5
6
  GroupChannelPreview,
7
+ Icon,
6
8
  LoadingSpinner,
7
9
  createStyleSheet,
8
10
  useUIKitTheme,
9
11
  } from '@sendbird/uikit-react-native-foundation';
10
- import Icon from '@sendbird/uikit-react-native-foundation/src/ui/Icon';
11
12
  import {
12
13
  SendbirdGroupChannel,
13
14
  SendbirdUser,
@@ -15,14 +16,13 @@ import {
15
16
  getFileType,
16
17
  isDifferentChannel,
17
18
  isMyMessage,
18
- useForceUpdate,
19
19
  useIIFE,
20
20
  useUniqId,
21
21
  } from '@sendbird/uikit-utils';
22
22
 
23
+ import ChannelCover from '../components/ChannelCover';
24
+ import { DEFAULT_LONG_PRESS_DELAY } from '../constants';
23
25
  import { useLocalization, useSendbirdChat } from '../hooks/useContext';
24
- import ChannelCover from './ChannelCover';
25
- import SBUPressable from './SBUPressable';
26
26
 
27
27
  const iconMapper = { audio: 'file-audio', image: 'photo', video: 'play', file: 'file-document' } as const;
28
28
 
@@ -37,7 +37,6 @@ const GroupChannelPreviewContainer = ({ onPress, onLongPress, channel }: Props)
37
37
  const { colors } = useUIKitTheme();
38
38
 
39
39
  const [typingUsers, setTypingUsers] = useState<SendbirdUser[]>([]);
40
- const forceUpdate = useForceUpdate();
41
40
 
42
41
  if (features.channelListTypingIndicatorEnabled) {
43
42
  const typingId = useUniqId('GroupChannelPreviewContainer');
@@ -49,25 +48,7 @@ const GroupChannelPreviewContainer = ({ onPress, onLongPress, channel }: Props)
49
48
  });
50
49
  }
51
50
 
52
- if (features.channelListMessageReceiptStatusEnabled) {
53
- const receiptId = useUniqId('GroupChannelPreviewContainer');
54
- useChannelHandler(sdk, `GroupChannelPreviewContainer_ReceiptStatus_${receiptId}`, {
55
- onDeliveryReceiptUpdated(eventChannel) {
56
- if (isDifferentChannel(channel, eventChannel)) return;
57
- if (!eventChannel.isGroupChannel() || !eventChannel.lastMessage) return;
58
- if (!isMyMessage(eventChannel.lastMessage, currentUser?.userId)) return;
59
-
60
- forceUpdate();
61
- },
62
- onReadReceiptUpdated(eventChannel) {
63
- if (isDifferentChannel(channel, eventChannel)) return;
64
- if (!eventChannel.isGroupChannel() || !eventChannel.lastMessage) return;
65
- if (!isMyMessage(eventChannel.lastMessage, currentUser?.userId)) return;
66
-
67
- forceUpdate();
68
- },
69
- });
70
- }
51
+ const outgoingStatus = useMessageOutgoingStatus(sdk, channel, channel.lastMessage);
71
52
 
72
53
  const bodyText = useIIFE(() => {
73
54
  if (typingUsers.length > 0) return STRINGS.LABELS.TYPING_INDICATOR_TYPINGS(typingUsers) || '';
@@ -76,6 +57,7 @@ const GroupChannelPreviewContainer = ({ onPress, onLongPress, channel }: Props)
76
57
 
77
58
  const bodyIcon = useIIFE(() => {
78
59
  if (!channel.lastMessage?.isFileMessage()) return undefined;
60
+ if (typingUsers.length > 0) return undefined;
79
61
  return iconMapper[getFileType(channel.lastMessage.type || getFileExtension(channel.lastMessage.name))];
80
62
  });
81
63
 
@@ -84,30 +66,31 @@ const GroupChannelPreviewContainer = ({ onPress, onLongPress, channel }: Props)
84
66
  if (!features.channelListMessageReceiptStatusEnabled) return undefined;
85
67
  if (!isMyMessage(channel.lastMessage, currentUser?.userId)) return undefined;
86
68
 
87
- if (channel.lastMessage.sendingStatus === 'pending') {
69
+ if (outgoingStatus === 'PENDING') {
88
70
  return <LoadingSpinner size={16} style={styles.titleCaptionIcon} />;
89
71
  }
90
72
 
91
- if (channel.lastMessage.sendingStatus === 'failed') {
73
+ if (outgoingStatus === 'FAILED') {
92
74
  return <Icon icon={'error'} size={16} color={colors.error} style={styles.titleCaptionIcon} />;
93
75
  }
94
76
 
95
- if (channel.getUnreadMemberCount(channel.lastMessage) === 0) {
96
- return <Icon icon={'done-all'} size={16} color={colors.secondary} style={styles.titleCaptionIcon} />;
77
+ if (outgoingStatus === 'UNDELIVERED') {
78
+ return <Icon icon={'done'} size={16} color={colors.onBackground03} containerStyle={styles.titleCaptionIcon} />;
97
79
  }
98
80
 
99
- if (features.deliveryReceiptEnabled) {
100
- if (channel.getUndeliveredMemberCount(channel.lastMessage) === 0) {
101
- return <Icon icon={'done-all'} size={16} color={colors.onBackground03} style={styles.titleCaptionIcon} />;
102
- }
103
- return <Icon icon={'done'} size={16} color={colors.onBackground03} containerStyle={styles.titleCaptionIcon} />;
81
+ if (outgoingStatus === 'DELIVERED' || outgoingStatus === 'UNREAD') {
82
+ return <Icon icon={'done-all'} size={16} color={colors.onBackground03} style={styles.titleCaptionIcon} />;
83
+ }
84
+
85
+ if (outgoingStatus === 'READ') {
86
+ return <Icon icon={'done-all'} size={16} color={colors.secondary} style={styles.titleCaptionIcon} />;
104
87
  }
105
88
 
106
- return <Icon icon={'done-all'} size={16} color={colors.onBackground03} style={styles.titleCaptionIcon} />;
89
+ return undefined;
107
90
  });
108
91
 
109
92
  return (
110
- <SBUPressable onPress={onPress} onLongPress={onLongPress}>
93
+ <Pressable delayLongPress={DEFAULT_LONG_PRESS_DELAY} onPress={onPress} onLongPress={onLongPress}>
111
94
  <GroupChannelPreview
112
95
  customCover={<ChannelCover channel={channel} size={56} />}
113
96
  coverUrl={channel.coverUrl}
@@ -121,7 +104,7 @@ const GroupChannelPreviewContainer = ({ onPress, onLongPress, channel }: Props)
121
104
  frozen={channel.isFrozen}
122
105
  notificationOff={channel.myPushTriggerOption === 'off'}
123
106
  />
124
- </SBUPressable>
107
+ </Pressable>
125
108
  );
126
109
  };
127
110
 
@@ -1,8 +1,8 @@
1
1
  import React, { ErrorInfo } from 'react';
2
2
  import { View } from 'react-native';
3
3
 
4
- import TypedPlaceholder from './components/TypedPlaceholder';
5
- import type { ErrorBoundaryProps } from './types';
4
+ import TypedPlaceholder from '../components/TypedPlaceholder';
5
+ import type { ErrorBoundaryProps } from '../types';
6
6
 
7
7
  const DefaultErrorBoundaryComponent = (props: ErrorBoundaryProps) => {
8
8
  return (
@@ -12,7 +12,7 @@ const DefaultErrorBoundaryComponent = (props: ErrorBoundaryProps) => {
12
12
  );
13
13
  };
14
14
 
15
- class InternalErrorBoundary extends React.PureComponent<{
15
+ class InternalErrorBoundaryContainer extends React.PureComponent<{
16
16
  onError?: (props: ErrorBoundaryProps) => void;
17
17
  ErrorInfoComponent?: (props: ErrorBoundaryProps) => JSX.Element;
18
18
  children?: React.ReactNode;
@@ -50,4 +50,4 @@ class InternalErrorBoundary extends React.PureComponent<{
50
50
  };
51
51
  }
52
52
 
53
- export default InternalErrorBoundary;
53
+ export default InternalErrorBoundaryContainer;
@@ -14,23 +14,23 @@ import {
14
14
  } from '@sendbird/uikit-react-native-foundation';
15
15
  import type { SendbirdChatSDK } from '@sendbird/uikit-utils';
16
16
 
17
- import InternalErrorBoundary from './InternalErrorBoundary';
18
- import InternalLocalCacheStorage from './InternalLocalCacheStorage';
19
- import { LocalizationProvider } from './contexts/Localization';
20
- import { PlatformServiceProvider } from './contexts/PlatformService';
21
- import { SendbirdChatProvider } from './contexts/SendbirdChat';
22
- import { useLocalization } from './hooks/useContext';
23
- import StringSetEn from './localization/StringSet.en';
24
- import type { StringSet } from './localization/StringSet.type';
25
- import SBUDynamicModule from './platform/dynamicModule';
17
+ import { LocalizationProvider } from '../contexts/Localization';
18
+ import { PlatformServiceProvider } from '../contexts/PlatformService';
19
+ import { SendbirdChatProvider } from '../contexts/SendbirdChat';
20
+ import { useLocalization } from '../hooks/useContext';
21
+ import InternalLocalCacheStorage from '../libs/InternalLocalCacheStorage';
22
+ import StringSetEn from '../localization/StringSet.en';
23
+ import type { StringSet } from '../localization/StringSet.type';
24
+ import SBUDynamicModule from '../platform/dynamicModule';
26
25
  import type {
27
26
  ClipboardServiceInterface,
28
27
  FileServiceInterface,
29
28
  MediaServiceInterface,
30
29
  NotificationServiceInterface,
31
- } from './platform/types';
32
- import type { ErrorBoundaryProps, LocalCacheStorage } from './types';
33
- import VERSION from './version';
30
+ } from '../platform/types';
31
+ import type { ErrorBoundaryProps, LocalCacheStorage } from '../types';
32
+ import VERSION from '../version';
33
+ import InternalErrorBoundaryContainer from './InternalErrorBoundaryContainer';
34
34
 
35
35
  const NetInfo = SBUDynamicModule.get('@react-native-community/netinfo', 'warn');
36
36
 
@@ -159,7 +159,7 @@ const SendbirdUIKitContainer = ({
159
159
  >
160
160
  <LocalizedDialogProvider>
161
161
  <ToastProvider dismissTimeout={toast?.dismissTimeout}>
162
- <InternalErrorBoundary {...errorBoundary}>{children}</InternalErrorBoundary>
162
+ <InternalErrorBoundaryContainer {...errorBoundary}>{children}</InternalErrorBoundaryContainer>
163
163
  </ToastProvider>
164
164
  </LocalizedDialogProvider>
165
165
  </HeaderStyleProvider>