@sendbird/uikit-react-native 3.9.6 → 3.10.0

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 (59) hide show
  1. package/lib/commonjs/components/ChannelMessageList/index.js +57 -9
  2. package/lib/commonjs/components/ChannelMessageList/index.js.map +1 -1
  3. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageNewLine.js +53 -0
  4. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageNewLine.js.map +1 -0
  5. package/lib/commonjs/components/GroupChannelMessageRenderer/index.js +5 -0
  6. package/lib/commonjs/components/GroupChannelMessageRenderer/index.js.map +1 -1
  7. package/lib/commonjs/components/UnreadMessagesFloating.js +77 -0
  8. package/lib/commonjs/components/UnreadMessagesFloating.js.map +1 -0
  9. package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js +156 -7
  10. package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
  11. package/lib/commonjs/domain/groupChannel/types.js.map +1 -1
  12. package/lib/commonjs/fragments/createGroupChannelFragment.js +57 -3
  13. package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
  14. package/lib/commonjs/localization/StringSet.type.js.map +1 -1
  15. package/lib/commonjs/localization/createBaseStringSet.js +16 -2
  16. package/lib/commonjs/localization/createBaseStringSet.js.map +1 -1
  17. package/lib/commonjs/version.js +1 -1
  18. package/lib/commonjs/version.js.map +1 -1
  19. package/lib/module/components/ChannelMessageList/index.js +57 -9
  20. package/lib/module/components/ChannelMessageList/index.js.map +1 -1
  21. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageNewLine.js +46 -0
  22. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageNewLine.js.map +1 -0
  23. package/lib/module/components/GroupChannelMessageRenderer/index.js +5 -0
  24. package/lib/module/components/GroupChannelMessageRenderer/index.js.map +1 -1
  25. package/lib/module/components/UnreadMessagesFloating.js +70 -0
  26. package/lib/module/components/UnreadMessagesFloating.js.map +1 -0
  27. package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js +158 -9
  28. package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
  29. package/lib/module/domain/groupChannel/types.js.map +1 -1
  30. package/lib/module/fragments/createGroupChannelFragment.js +59 -5
  31. package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
  32. package/lib/module/localization/StringSet.type.js.map +1 -1
  33. package/lib/module/localization/createBaseStringSet.js +16 -2
  34. package/lib/module/localization/createBaseStringSet.js.map +1 -1
  35. package/lib/module/version.js +1 -1
  36. package/lib/module/version.js.map +1 -1
  37. package/lib/typescript/src/components/ChannelMessageList/index.d.ts +8 -1
  38. package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageNewLine.d.ts +6 -0
  39. package/lib/typescript/src/components/GroupChannelMessageRenderer/index.d.ts +1 -0
  40. package/lib/typescript/src/components/OpenChannelMessageRenderer/index.d.ts +1 -0
  41. package/lib/typescript/src/components/UnreadMessagesFloating.d.ts +8 -0
  42. package/lib/typescript/src/containers/SendbirdUIKitContainer.d.ts +1 -1
  43. package/lib/typescript/src/domain/groupChannel/component/GroupChannelMessageList.d.ts +6 -1
  44. package/lib/typescript/src/domain/groupChannel/types.d.ts +13 -1
  45. package/lib/typescript/src/domain/openChannel/component/OpenChannelHeader.d.ts +1 -1
  46. package/lib/typescript/src/hooks/useChannelInputItems.d.ts +1 -1
  47. package/lib/typescript/src/localization/StringSet.type.d.ts +3 -0
  48. package/lib/typescript/src/version.d.ts +1 -1
  49. package/package.json +8 -7
  50. package/src/components/ChannelMessageList/index.tsx +71 -5
  51. package/src/components/GroupChannelMessageRenderer/GroupChannelMessageNewLine.tsx +45 -0
  52. package/src/components/GroupChannelMessageRenderer/index.tsx +5 -0
  53. package/src/components/UnreadMessagesFloating.tsx +60 -0
  54. package/src/domain/groupChannel/component/GroupChannelMessageList.tsx +204 -5
  55. package/src/domain/groupChannel/types.ts +15 -0
  56. package/src/fragments/createGroupChannelFragment.tsx +67 -4
  57. package/src/localization/StringSet.type.ts +3 -0
  58. package/src/localization/createBaseStringSet.ts +16 -4
  59. package/src/version.ts +1 -1
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  declare const _default: React.MemoExoticComponent<({ onPressHeaderLeft, onPressHeaderRight, rightIconName }: {
3
- rightIconName: "search" | "stop" | "photo" | "recording" | "delete" | "message" | "done" | "user" | "add" | "chat-hide" | "chat-show" | "archive" | "arrow-left" | "audio-off-filled" | "audio-off" | "audio-on-filled" | "audio-on" | "ban" | "broadcast" | "camera" | "channels" | "chat-filled" | "chat" | "checkbox-off" | "checkbox-on" | "chevron-down" | "chevron-right" | "close" | "copy" | "create" | "document" | "done-all" | "download" | "edit" | "emoji-more" | "error" | "file-audio" | "file-document" | "freeze" | "gif" | "info" | "leave" | "members" | "moderation" | "more" | "mute" | "notifications-filled" | "notifications-off-filled" | "notifications" | "operator" | "pause" | "play" | "plus" | "question" | "radio-off" | "radio-on" | "refresh" | "remove" | "reply-filled" | "reply" | "send" | "settings-filled" | "spinner" | "streaming" | "supergroup" | "theme" | "thread" | "thumbnail-none" | "unarchive";
3
+ rightIconName: "search" | "stop" | "photo" | "recording" | "delete" | "message" | "done" | "user" | "add" | "chat-hide" | "chat-show" | "archive" | "arrow-left" | "audio-off-filled" | "audio-off" | "audio-on-filled" | "audio-on" | "ban" | "broadcast" | "camera" | "channels" | "chat-filled" | "chat" | "checkbox-off" | "checkbox-on" | "chevron-down" | "chevron-right" | "close" | "copy" | "create" | "document" | "done-all" | "download" | "edit" | "emoji-more" | "error" | "file-audio" | "file-document" | "freeze" | "gif" | "info" | "leave" | "mark-as-unread" | "members" | "moderation" | "more" | "mute" | "notifications-filled" | "notifications-off-filled" | "notifications" | "operator" | "pause" | "play" | "plus" | "question" | "radio-off" | "radio-on" | "refresh" | "remove" | "reply-filled" | "reply" | "send" | "settings-filled" | "spinner" | "streaming" | "supergroup" | "theme" | "thread" | "thumbnail-none" | "unarchive";
4
4
  onPressHeaderLeft: () => void;
5
5
  onPressHeaderRight: () => void;
6
6
  }) => React.JSX.Element>;
@@ -1,7 +1,7 @@
1
1
  import { SendbirdChannel } from '@sendbird/uikit-utils';
2
2
  import { FileType } from '../platform/types';
3
3
  export declare const useChannelInputItems: (channel: SendbirdChannel, sendFileMessage: (file: FileType) => void) => {
4
- icon?: "search" | "stop" | "photo" | "recording" | "delete" | "message" | "done" | "user" | "add" | "chat-hide" | "chat-show" | "archive" | "arrow-left" | "audio-off-filled" | "audio-off" | "audio-on-filled" | "audio-on" | "ban" | "broadcast" | "camera" | "channels" | "chat-filled" | "chat" | "checkbox-off" | "checkbox-on" | "chevron-down" | "chevron-right" | "close" | "copy" | "create" | "document" | "done-all" | "download" | "edit" | "emoji-more" | "error" | "file-audio" | "file-document" | "freeze" | "gif" | "info" | "leave" | "members" | "moderation" | "more" | "mute" | "notifications-filled" | "notifications-off-filled" | "notifications" | "operator" | "pause" | "play" | "plus" | "question" | "radio-off" | "radio-on" | "refresh" | "remove" | "reply-filled" | "reply" | "send" | "settings-filled" | "spinner" | "streaming" | "supergroup" | "theme" | "thread" | "thumbnail-none" | "unarchive" | undefined;
4
+ icon?: "search" | "stop" | "photo" | "recording" | "delete" | "message" | "done" | "user" | "add" | "chat-hide" | "chat-show" | "archive" | "arrow-left" | "audio-off-filled" | "audio-off" | "audio-on-filled" | "audio-on" | "ban" | "broadcast" | "camera" | "channels" | "chat-filled" | "chat" | "checkbox-off" | "checkbox-on" | "chevron-down" | "chevron-right" | "close" | "copy" | "create" | "document" | "done-all" | "download" | "edit" | "emoji-more" | "error" | "file-audio" | "file-document" | "freeze" | "gif" | "info" | "leave" | "mark-as-unread" | "members" | "moderation" | "more" | "mute" | "notifications-filled" | "notifications-off-filled" | "notifications" | "operator" | "pause" | "play" | "plus" | "question" | "radio-off" | "radio-on" | "refresh" | "remove" | "reply-filled" | "reply" | "send" | "settings-filled" | "spinner" | "streaming" | "supergroup" | "theme" | "thread" | "thumbnail-none" | "unarchive" | undefined;
5
5
  iconColor?: string | undefined;
6
6
  title: string;
7
7
  titleColor?: string | undefined;
@@ -96,6 +96,8 @@ export interface StringSet {
96
96
  /** GroupChannel > List */
97
97
  LIST_DATE_SEPARATOR: (date: Date, locale?: Locale) => string;
98
98
  LIST_BUTTON_NEW_MSG: (newMessages: SendbirdMessage[]) => string;
99
+ LIST_FLOATING_UNREAD_MSG: (unreadMessageCount: number) => string;
100
+ LIST_NEW_LINE: string;
99
101
  /** GroupChannel > Message bubble */
100
102
  MESSAGE_BUBBLE_TIME: (message: SendbirdMessage, locale?: Locale) => string;
101
103
  MESSAGE_BUBBLE_FILE_TITLE: (message: SendbirdFileMessage) => string;
@@ -272,6 +274,7 @@ export interface StringSet {
272
274
  CHANNEL_MESSAGE_DELETE: string;
273
275
  CHANNEL_MESSAGE_REPLY: string;
274
276
  CHANNEL_MESSAGE_THREAD: string;
277
+ CHANNEL_MESSAGE_MARK_AS_UNREAD: string;
275
278
  /** Channel > Message > Delete confirm **/
276
279
  CHANNEL_MESSAGE_DELETE_CONFIRM_TITLE: string;
277
280
  CHANNEL_MESSAGE_DELETE_CONFIRM_OK: string;
@@ -1,2 +1,2 @@
1
- declare const VERSION = "3.9.6";
1
+ declare const VERSION = "3.10.0";
2
2
  export default VERSION;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendbird/uikit-react-native",
3
- "version": "3.9.6",
3
+ "version": "3.10.0",
4
4
  "description": "Sendbird UIKit for React Native: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.",
5
5
  "keywords": [
6
6
  "sendbird",
@@ -60,10 +60,10 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "@openspacelabs/react-native-zoomable-view": "^2.1.5",
63
- "@sendbird/uikit-chat-hooks": "3.9.6",
64
- "@sendbird/uikit-react-native-foundation": "3.9.6",
65
- "@sendbird/uikit-tools": "0.0.7",
66
- "@sendbird/uikit-utils": "3.9.6"
63
+ "@sendbird/uikit-chat-hooks": "3.10.0",
64
+ "@sendbird/uikit-react-native-foundation": "3.10.0",
65
+ "@sendbird/uikit-tools": "0.0.10",
66
+ "@sendbird/uikit-utils": "3.10.0"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@bam.tech/react-native-image-resizer": "^3.0.4",
@@ -111,8 +111,9 @@
111
111
  "@react-native-community/netinfo": ">=9.3.0",
112
112
  "@react-native-documents/picker": ">=10.0.0",
113
113
  "@react-native-firebase/messaging": ">=14.4.0",
114
- "@sendbird/chat": "^4.16.0",
114
+ "@sendbird/chat": "^4.19.2",
115
115
  "@sendbird/react-native-scrollview-enhancer": "*",
116
+ "@sendbird/uikit-tools": ">=0.0.10",
116
117
  "date-fns": ">=2.28.0",
117
118
  "expo-av": ">=12.0.4",
118
119
  "expo-clipboard": ">=2.1.1",
@@ -217,5 +218,5 @@
217
218
  ]
218
219
  ]
219
220
  },
220
- "gitHead": "639b760dc4a6d804be16ed06aec680aefa9a8875"
221
+ "gitHead": "01b356019dead8053d3469bf5a40c69d66c5b980"
221
222
  }
@@ -40,6 +40,7 @@ import {
40
40
  import SBUUtils from '../../libs/SBUUtils';
41
41
  import ChatFlatList from '../ChatFlatList';
42
42
  import { ReactionAddons } from '../ReactionAddons';
43
+ import { UnreadMessagesFloatingProps } from '../UnreadMessagesFloating';
43
44
 
44
45
  type PressActions = { onPress?: () => void; onLongPress?: () => void; bottomSheetItem?: BottomSheetItem };
45
46
  type HandleableMessage = SendbirdUserMessage | SendbirdFileMessage;
@@ -50,6 +51,7 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
50
51
  channel: T;
51
52
  messages: SendbirdMessage[];
52
53
  newMessages: SendbirdMessage[];
54
+ unreadFirstMessage?: SendbirdMessage;
53
55
  searchItem?: { startingPoint: number };
54
56
 
55
57
  scrolledAwayFromBottom: boolean;
@@ -68,6 +70,7 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
68
70
  onResendFailedMessage: (failedMessage: HandleableMessage) => Promise<HandleableMessage | void>;
69
71
  onPressParentMessage?: (parentMessage: SendbirdMessage, childMessage: HandleableMessage) => void;
70
72
  onPressMediaMessage?: (message: SendbirdFileMessage, deleteMessage: () => Promise<void>, uri: string) => void;
73
+ onPressMarkAsUnreadMessage?: (message: HandleableMessage) => void;
71
74
 
72
75
  renderMessage: (props: {
73
76
  focused: boolean;
@@ -84,14 +87,18 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
84
87
  enableMessageGrouping: ChannelMessageListProps<T>['enableMessageGrouping'];
85
88
  bottomSheetItem?: BottomSheetItem;
86
89
  isFirstItem: boolean;
90
+ isFirstUnreadMessage?: boolean;
87
91
  hideParentMessage?: boolean;
88
92
  }) => React.ReactElement | null;
89
93
  renderNewMessagesButton:
90
94
  | null
91
95
  | ((props: { visible: boolean; onPress: () => void; newMessages: SendbirdMessage[] }) => React.ReactElement | null);
92
96
  renderScrollToBottomButton: null | ((props: { visible: boolean; onPress: () => void }) => React.ReactElement | null);
97
+ renderUnreadMessagesFloating?: null | ((props: UnreadMessagesFloatingProps) => React.ReactElement | null);
98
+ unreadMessagesFloatingProps?: UnreadMessagesFloatingProps;
93
99
  flatListComponent?: React.ComponentType<FlatListProps<SendbirdMessage>>;
94
100
  flatListProps?: Omit<FlatListProps<SendbirdMessage>, 'data' | 'renderItem'>;
101
+ onViewableItemsChanged?: FlatListProps<SendbirdMessage>['onViewableItemsChanged'];
95
102
  } & {
96
103
  ref?: Ref<FlatList<SendbirdMessage>> | undefined;
97
104
  };
@@ -108,12 +115,15 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
108
115
  onResendFailedMessage,
109
116
  onPressMediaMessage,
110
117
  onPressParentMessage,
118
+ onPressMarkAsUnreadMessage,
111
119
  currentUserId,
120
+ renderUnreadMessagesFloating,
112
121
  renderNewMessagesButton,
113
122
  renderScrollToBottomButton,
114
123
  renderMessage,
115
124
  messages,
116
125
  newMessages,
126
+ unreadFirstMessage,
117
127
  enableMessageGrouping,
118
128
  onScrolledAwayFromBottom,
119
129
  scrolledAwayFromBottom,
@@ -121,8 +131,10 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
121
131
  onTopReached,
122
132
  flatListComponent,
123
133
  flatListProps,
134
+ onViewableItemsChanged,
124
135
  onPressNewMessagesButton,
125
136
  onPressScrollToBottomButton,
137
+ unreadMessagesFloatingProps,
126
138
  }: ChannelMessageListProps<T>,
127
139
  ref: React.ForwardedRef<FlatList<SendbirdMessage>>,
128
140
  ) => {
@@ -139,6 +151,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
139
151
  onDeleteMessage,
140
152
  onResendFailedMessage,
141
153
  onPressMediaMessage,
154
+ onPressMarkAsUnreadMessage,
142
155
  });
143
156
 
144
157
  const renderItem: ListRenderItem<SendbirdMessage> = useFreshCallback(({ item, index }) => {
@@ -147,6 +160,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
147
160
  message: item,
148
161
  prevMessage: messages[index + 1],
149
162
  nextMessage: messages[index - 1],
163
+ isFirstUnreadMessage: unreadFirstMessage?.messageId === item.messageId,
150
164
  onPress,
151
165
  onLongPress,
152
166
  onPressParentMessage,
@@ -166,9 +180,21 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
166
180
  {channel.isFrozen && (
167
181
  <ChannelFrozenBanner style={styles.frozenBanner} text={STRINGS.LABELS.CHANNEL_MESSAGE_LIST_FROZEN} />
168
182
  )}
183
+ {renderUnreadMessagesFloating && (
184
+ <View
185
+ style={[channel.isFrozen ? styles.unreadMsgFloatingWhenFrozen : styles.unreadMsgFloating, safeAreaLayout]}
186
+ >
187
+ {renderUnreadMessagesFloating({
188
+ visible: unreadMessagesFloatingProps?.visible ?? false,
189
+ onPressClose: () => unreadMessagesFloatingProps?.onPressClose(),
190
+ unreadMessageCount: unreadMessagesFloatingProps?.unreadMessageCount ?? 0,
191
+ })}
192
+ </View>
193
+ )}
169
194
  <ChatFlatList
170
195
  flatListComponent={flatListComponent}
171
196
  {...flatListProps}
197
+ onViewableItemsChanged={onViewableItemsChanged}
172
198
  onTopReached={onTopReached}
173
199
  onBottomReached={onBottomReached}
174
200
  onScrolledAwayFromBottom={onScrolledAwayFromBottom}
@@ -212,6 +238,7 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
212
238
  onReplyInThreadMessage,
213
239
  onDeleteMessage,
214
240
  onPressMediaMessage,
241
+ onPressMarkAsUnreadMessage,
215
242
  }: Pick<
216
243
  ChannelMessageListProps<T>,
217
244
  | 'channel'
@@ -222,6 +249,7 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
222
249
  | 'onDeleteMessage'
223
250
  | 'onResendFailedMessage'
224
251
  | 'onPressMediaMessage'
252
+ | 'onPressMarkAsUnreadMessage'
225
253
  >): CreateMessagePressActions => {
226
254
  const handlers = useSBUHandlers();
227
255
  const { colors } = useUIKitTheme();
@@ -281,6 +309,10 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
281
309
  }
282
310
  };
283
311
 
312
+ const onMarkAsUnread = (message: HandleableMessage) => {
313
+ onPressMarkAsUnreadMessage?.(message);
314
+ };
315
+
284
316
  const openSheetForFailedMessage = (message: HandleableMessage) => {
285
317
  openSheet({
286
318
  sheetItems: [
@@ -323,6 +355,11 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
323
355
  title: STRINGS.LABELS.CHANNEL_MESSAGE_COPY,
324
356
  onPress: () => onCopyText(message),
325
357
  }),
358
+ markAsUnread: (message: HandleableMessage) => ({
359
+ icon: 'mark-as-unread' as const,
360
+ title: STRINGS.LABELS.CHANNEL_MESSAGE_MARK_AS_UNREAD,
361
+ onPress: () => onMarkAsUnread(message),
362
+ }),
326
363
  edit: (message: HandleableMessage) => ({
327
364
  icon: 'edit' as const,
328
365
  title: STRINGS.LABELS.CHANNEL_MESSAGE_EDIT,
@@ -356,9 +393,19 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
356
393
  if (message.isUserMessage()) {
357
394
  sheetItems.push(menu.copy(message));
358
395
  if (!channel.isEphemeral) {
359
- if (isMyMessage(message, currentUserId) && message.sendingStatus === 'succeeded') {
360
- sheetItems.push(menu.edit(message));
361
- sheetItems.push(menu.delete(message));
396
+ if (message.sendingStatus === 'succeeded') {
397
+ const isMyMsg = isMyMessage(message, currentUserId);
398
+ if (isMyMsg) {
399
+ sheetItems.push(menu.edit(message));
400
+ }
401
+
402
+ if (channel.isGroupChannel() && sbOptions.uikit.groupChannel.channel.enableMarkAsUnread) {
403
+ sheetItems.push(menu.markAsUnread(message));
404
+ }
405
+
406
+ if (isMyMsg) {
407
+ sheetItems.push(menu.delete(message));
408
+ }
362
409
  }
363
410
  if (channel.isGroupChannel()) {
364
411
  if (sbOptions.uikit.groupChannel.channel.replyType === 'thread' && onReplyInThreadMessage !== undefined) {
@@ -375,9 +422,16 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
375
422
  sheetItems.push(menu.download(message));
376
423
  }
377
424
  if (!channel.isEphemeral) {
378
- if (isMyMessage(message, currentUserId) && message.sendingStatus === 'succeeded') {
379
- sheetItems.push(menu.delete(message));
425
+ if (message.sendingStatus === 'succeeded') {
426
+ if (channel.isGroupChannel() && sbOptions.uikit.groupChannel.channel.enableMarkAsUnread) {
427
+ sheetItems.push(menu.markAsUnread(message));
428
+ }
429
+
430
+ if (isMyMessage(message, currentUserId)) {
431
+ sheetItems.push(menu.delete(message));
432
+ }
380
433
  }
434
+
381
435
  if (channel.isGroupChannel()) {
382
436
  if (sbOptions.uikit.groupChannel.channel.replyType === 'thread' && onReplyInThreadMessage !== undefined) {
383
437
  sheetItems.push(menu.replyInThread(message));
@@ -446,6 +500,18 @@ const styles = createStyleSheet({
446
500
  frozenListPadding: {
447
501
  paddingBottom: 32,
448
502
  },
503
+ unreadMsgFloating: {
504
+ position: 'absolute',
505
+ zIndex: 999,
506
+ top: 12,
507
+ alignSelf: 'center',
508
+ },
509
+ unreadMsgFloatingWhenFrozen: {
510
+ position: 'absolute',
511
+ zIndex: 999,
512
+ top: 40,
513
+ alignSelf: 'center',
514
+ },
449
515
  newMsgButton: {
450
516
  position: 'absolute',
451
517
  zIndex: 999,
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
+
4
+ import { Box, Text, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
5
+
6
+ import { useLocalization } from '../../hooks/useContext';
7
+
8
+ type Props = {
9
+ shouldRenderNewLine?: boolean;
10
+ };
11
+
12
+ const GroupChannelMessageNewLine = ({ shouldRenderNewLine }: Props) => {
13
+ if (!shouldRenderNewLine) return null;
14
+
15
+ const { STRINGS } = useLocalization();
16
+ const { colors } = useUIKitTheme();
17
+
18
+ return (
19
+ <View style={styles.container}>
20
+ <Box backgroundColor={colors.primary} style={styles.line} />
21
+ <Text caption3 numberOfLines={1} color={colors.primary} style={styles.label}>
22
+ {STRINGS.GROUP_CHANNEL.LIST_NEW_LINE}
23
+ </Text>
24
+ <Box backgroundColor={colors.primary} style={styles.line} />
25
+ </View>
26
+ );
27
+ };
28
+
29
+ const styles = StyleSheet.create({
30
+ container: {
31
+ width: '100%',
32
+ flexDirection: 'row',
33
+ alignItems: 'center',
34
+ marginBottom: 16,
35
+ },
36
+ line: {
37
+ flex: 1,
38
+ height: 1,
39
+ },
40
+ label: {
41
+ marginHorizontal: 4,
42
+ },
43
+ });
44
+
45
+ export default React.memo(GroupChannelMessageNewLine);
@@ -30,6 +30,7 @@ import { TypingIndicatorType } from '../../types';
30
30
  import { ReactionAddons } from '../ReactionAddons';
31
31
  import GroupChannelMessageDateSeparator from './GroupChannelMessageDateSeparator';
32
32
  import GroupChannelMessageFocusAnimation from './GroupChannelMessageFocusAnimation';
33
+ import GroupChannelMessageNewLine from './GroupChannelMessageNewLine';
33
34
  import GroupChannelMessageOutgoingStatus from './GroupChannelMessageOutgoingStatus';
34
35
  import GroupChannelMessageParentMessage from './GroupChannelMessageParentMessage';
35
36
  import GroupChannelMessageReplyInfo from './GroupChannelMessageReplyInfo';
@@ -46,6 +47,7 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
46
47
  focused,
47
48
  prevMessage,
48
49
  nextMessage,
50
+ isFirstUnreadMessage,
49
51
  hideParentMessage,
50
52
  }) => {
51
53
  const handlers = useSBUHandlers();
@@ -310,9 +312,12 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
310
312
  }
311
313
  });
312
314
 
315
+ const shouldRenderNewLine = sbOptions.uikit.groupChannel.channel.enableMarkAsUnread && isFirstUnreadMessage;
316
+
313
317
  return (
314
318
  <Box paddingHorizontal={16} marginBottom={messageGap}>
315
319
  <GroupChannelMessageDateSeparator message={message} prevMessage={prevMessage} />
320
+ <GroupChannelMessageNewLine shouldRenderNewLine={shouldRenderNewLine} />
316
321
  <GroupChannelMessageFocusAnimation focused={focused}>{renderMessage()}</GroupChannelMessageFocusAnimation>
317
322
  </Box>
318
323
  );
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ import { Platform, TouchableOpacity, View } from 'react-native';
3
+
4
+ import { Icon, Text, createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
5
+
6
+ import { useLocalization } from '../hooks/useContext';
7
+
8
+ export type UnreadMessagesFloatingProps = {
9
+ unreadMessageCount: number;
10
+ visible: boolean;
11
+ onPressClose: () => void;
12
+ };
13
+ const UnreadMessagesFloating = ({ unreadMessageCount, visible, onPressClose }: UnreadMessagesFloatingProps) => {
14
+ const { STRINGS } = useLocalization();
15
+ const { select, palette, colors } = useUIKitTheme();
16
+ if (unreadMessageCount <= 0 || !visible) return null;
17
+ return (
18
+ <View
19
+ style={[
20
+ styles.container,
21
+ { backgroundColor: select({ dark: palette.background400, light: palette.background50 }) },
22
+ ]}
23
+ >
24
+ <Text body2 color={colors.onBackground02}>
25
+ {STRINGS.GROUP_CHANNEL.LIST_FLOATING_UNREAD_MSG(unreadMessageCount)}
26
+ </Text>
27
+ <TouchableOpacity
28
+ onPress={onPressClose}
29
+ style={{ marginLeft: 4 }}
30
+ hitSlop={{ top: 12, bottom: 12, left: 14, right: 38 }}
31
+ >
32
+ <Icon icon={'close'} size={14} />
33
+ </TouchableOpacity>
34
+ </View>
35
+ );
36
+ };
37
+
38
+ const styles = createStyleSheet({
39
+ container: {
40
+ flexDirection: 'row',
41
+ justifyContent: 'flex-start',
42
+ alignItems: 'center',
43
+ paddingHorizontal: 16,
44
+ paddingVertical: 12,
45
+ borderRadius: 20,
46
+ ...Platform.select({
47
+ android: {
48
+ elevation: 3,
49
+ },
50
+ ios: {
51
+ shadowColor: 'black',
52
+ shadowRadius: 3,
53
+ shadowOffset: { width: 0, height: 4 },
54
+ shadowOpacity: 0.08,
55
+ },
56
+ }),
57
+ },
58
+ });
59
+
60
+ export default React.memo(UnreadMessagesFloating);