stream-chat-react-native-core 6.7.3-beta.1 → 6.7.3-beta.3

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 (64) hide show
  1. package/lib/commonjs/components/Channel/Channel.js +296 -293
  2. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  3. package/lib/commonjs/components/Channel/hooks/useMessageListPagination.js +133 -147
  4. package/lib/commonjs/components/Channel/hooks/useMessageListPagination.js.map +1 -1
  5. package/lib/commonjs/components/KeyboardCompatibleView/KeyboardCompatibleView.js +7 -12
  6. package/lib/commonjs/components/KeyboardCompatibleView/KeyboardCompatibleView.js.map +1 -1
  7. package/lib/commonjs/components/MessageList/MessageList.js +167 -179
  8. package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
  9. package/lib/commonjs/components/MessageList/hooks/useMessageList.js +60 -37
  10. package/lib/commonjs/components/MessageList/hooks/useMessageList.js.map +1 -1
  11. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +450 -459
  12. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  13. package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
  14. package/lib/commonjs/hooks/index.js +11 -0
  15. package/lib/commonjs/hooks/index.js.map +1 -1
  16. package/lib/commonjs/hooks/useStableCallback.js +13 -0
  17. package/lib/commonjs/hooks/useStableCallback.js.map +1 -0
  18. package/lib/commonjs/version.json +1 -1
  19. package/lib/module/components/Channel/Channel.js +296 -293
  20. package/lib/module/components/Channel/Channel.js.map +1 -1
  21. package/lib/module/components/Channel/hooks/useMessageListPagination.js +133 -147
  22. package/lib/module/components/Channel/hooks/useMessageListPagination.js.map +1 -1
  23. package/lib/module/components/KeyboardCompatibleView/KeyboardCompatibleView.js +7 -12
  24. package/lib/module/components/KeyboardCompatibleView/KeyboardCompatibleView.js.map +1 -1
  25. package/lib/module/components/MessageList/MessageList.js +167 -179
  26. package/lib/module/components/MessageList/MessageList.js.map +1 -1
  27. package/lib/module/components/MessageList/hooks/useMessageList.js +60 -37
  28. package/lib/module/components/MessageList/hooks/useMessageList.js.map +1 -1
  29. package/lib/module/contexts/messageInputContext/MessageInputContext.js +450 -459
  30. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  31. package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
  32. package/lib/module/hooks/index.js +11 -0
  33. package/lib/module/hooks/index.js.map +1 -1
  34. package/lib/module/hooks/useStableCallback.js +13 -0
  35. package/lib/module/hooks/useStableCallback.js.map +1 -0
  36. package/lib/module/version.json +1 -1
  37. package/lib/typescript/components/Channel/Channel.d.ts.map +1 -1
  38. package/lib/typescript/components/Channel/hooks/useMessageListPagination.d.ts +3 -3
  39. package/lib/typescript/components/Channel/hooks/useMessageListPagination.d.ts.map +1 -1
  40. package/lib/typescript/components/KeyboardCompatibleView/KeyboardCompatibleView.d.ts +3 -0
  41. package/lib/typescript/components/KeyboardCompatibleView/KeyboardCompatibleView.d.ts.map +1 -1
  42. package/lib/typescript/components/MessageList/MessageList.d.ts.map +1 -1
  43. package/lib/typescript/components/MessageList/hooks/useMessageList.d.ts +4 -0
  44. package/lib/typescript/components/MessageList/hooks/useMessageList.d.ts.map +1 -1
  45. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts.map +1 -1
  46. package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +1 -1
  47. package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts.map +1 -1
  48. package/lib/typescript/hooks/index.d.ts +1 -0
  49. package/lib/typescript/hooks/index.d.ts.map +1 -1
  50. package/lib/typescript/hooks/useStableCallback.d.ts +26 -0
  51. package/lib/typescript/hooks/useStableCallback.d.ts.map +1 -0
  52. package/package.json +1 -1
  53. package/src/components/Channel/Channel.tsx +462 -431
  54. package/src/components/Channel/__tests__/Channel.test.js +8 -3
  55. package/src/components/Channel/hooks/useMessageListPagination.tsx +152 -147
  56. package/src/components/KeyboardCompatibleView/KeyboardCompatibleView.tsx +6 -4
  57. package/src/components/MessageList/MessageList.tsx +147 -112
  58. package/src/components/MessageList/hooks/useMessageList.ts +69 -38
  59. package/src/contexts/messageInputContext/MessageInputContext.tsx +293 -267
  60. package/src/contexts/messageInputContext/__tests__/pickFile.test.tsx +2 -1
  61. package/src/contexts/messagesContext/MessagesContext.tsx +1 -0
  62. package/src/hooks/index.ts +1 -0
  63. package/src/hooks/useStableCallback.ts +37 -0
  64. package/src/version.json +1 -1
@@ -53,6 +53,7 @@ import {
53
53
  import { mergeThemes, ThemeProvider, useTheme } from '../../contexts/themeContext/ThemeContext';
54
54
  import { ThreadContextValue, useThreadContext } from '../../contexts/threadContext/ThreadContext';
55
55
 
56
+ import { useStableCallback } from '../../hooks';
56
57
  import { DefaultStreamChatGenerics, FileTypes } from '../../types/types';
57
58
 
58
59
  // This is just to make sure that the scrolling happens in a different task queue.
@@ -362,6 +363,14 @@ const MessageListWithContext = <
362
363
 
363
364
  const [autoscrollToRecent, setAutoscrollToRecent] = useState(false);
364
365
 
366
+ const maintainVisibleContentPosition = useMemo(
367
+ () => ({
368
+ autoscrollToTopThreshold: autoscrollToRecent ? 10 : undefined,
369
+ minIndexForVisible: 1,
370
+ }),
371
+ [autoscrollToRecent],
372
+ );
373
+
365
374
  /**
366
375
  * We want to call onEndReached and onStartReached only once, per content length.
367
376
  * We keep track of calls to these functions per content length, with following trackers.
@@ -392,8 +401,9 @@ const MessageListWithContext = <
392
401
  */
393
402
  const messageIdLastScrolledToRef = useRef<string>(undefined);
394
403
  const [hasMoved, setHasMoved] = useState(false);
395
- const [lastReceivedId, setLastReceivedId] = useState(
396
- getLastReceivedMessage(processedMessageList)?.id,
404
+ const lastReceivedId = useMemo(
405
+ () => getLastReceivedMessage(processedMessageList)?.id,
406
+ [processedMessageList],
397
407
  );
398
408
  const [scrollToBottomButtonVisible, setScrollToBottomButtonVisible] = useState(false);
399
409
 
@@ -404,7 +414,7 @@ const MessageListWithContext = <
404
414
  const channelRef = useRef(channel);
405
415
  channelRef.current = channel;
406
416
 
407
- const updateStickyHeaderDateIfNeeded = (viewableItems: ViewToken[]) => {
417
+ const updateStickyHeaderDateIfNeeded = useStableCallback((viewableItems: ViewToken[]) => {
408
418
  if (!viewableItems.length) {
409
419
  return;
410
420
  }
@@ -431,12 +441,12 @@ const MessageListWithContext = <
431
441
  setStickyHeaderDate(lastItem.item.created_at);
432
442
  }
433
443
  }
434
- };
444
+ });
435
445
 
436
446
  /**
437
447
  * This function should show or hide the unread indicator depending on the
438
448
  */
439
- const updateStickyUnreadIndicator = (viewableItems: ViewToken[]) => {
449
+ const updateStickyUnreadIndicator = useStableCallback((viewableItems: ViewToken[]) => {
440
450
  if (!viewableItems.length) {
441
451
  setIsUnreadNotificationOpen(false);
442
452
  return;
@@ -482,7 +492,7 @@ const MessageListWithContext = <
482
492
  setIsUnreadNotificationOpen(false);
483
493
  }
484
494
  }
485
- };
495
+ });
486
496
 
487
497
  /**
488
498
  * FlatList doesn't accept changeable function for onViewableItemsChanged prop.
@@ -580,9 +590,6 @@ const MessageListWithContext = <
580
590
  ]);
581
591
 
582
592
  useEffect(() => {
583
- const lastReceivedMessage = getLastReceivedMessage(processedMessageList);
584
- setLastReceivedId(lastReceivedMessage?.id);
585
-
586
593
  /**
587
594
  * Scroll down when
588
595
  * created_at timestamp of top message before update is lesser than created_at timestamp of top message after update - channel has resynced
@@ -678,7 +685,7 @@ const MessageListWithContext = <
678
685
  // eslint-disable-next-line react-hooks/exhaustive-deps
679
686
  }, [channel, rawMessageList, threadList]);
680
687
 
681
- const goToMessage = async (messageId: string) => {
688
+ const goToMessage = useStableCallback(async (messageId: string) => {
682
689
  const indexOfParentInMessageList = processedMessageList.findIndex(
683
690
  (message) => message?.id === messageId,
684
691
  );
@@ -706,7 +713,7 @@ const MessageListWithContext = <
706
713
  } catch (e) {
707
714
  console.warn('Error while scrolling to message', e);
708
715
  }
709
- };
716
+ });
710
717
 
711
718
  /**
712
719
  * Check if a messageId needs to be scrolled to after list loads, and scroll to it
@@ -749,78 +756,99 @@ const MessageListWithContext = <
749
756
  // TODO: do not apply on RN 0.73 and above
750
757
  const shouldApplyAndroidWorkaround = inverted && Platform.OS === 'android';
751
758
 
752
- const renderItem = ({
753
- index,
754
- item: message,
755
- }: {
756
- index: number;
757
- item: MessageType<StreamChatGenerics>;
758
- }) => {
759
- if (!channel || channel.disconnected || (!channel.initialized && !channel.offlineMode)) {
760
- return null;
761
- }
759
+ const renderItem = useCallback(
760
+ ({ index, item: message }: { index: number; item: MessageType<StreamChatGenerics> }) => {
761
+ if (!channel || channel.disconnected || (!channel.initialized && !channel.offlineMode)) {
762
+ return null;
763
+ }
762
764
 
763
- const createdAtTimestamp = message.created_at && new Date(message.created_at).getTime();
764
- const lastReadTimestamp = channelUnreadState?.last_read.getTime();
765
- const isNewestMessage = index === 0;
766
- const isLastReadMessage =
767
- channelUnreadState?.last_read_message_id === message.id ||
768
- (!channelUnreadState?.unread_messages && createdAtTimestamp === lastReadTimestamp);
769
-
770
- const showUnreadSeparator =
771
- isLastReadMessage &&
772
- !isNewestMessage &&
773
- // The `channelUnreadState?.first_unread_message_id` is here for sent messages unread label
774
- (!!channelUnreadState?.first_unread_message_id || !!channelUnreadState?.unread_messages);
775
-
776
- const showUnreadUnderlay = !!shouldShowUnreadUnderlay && showUnreadSeparator;
777
-
778
- const wrapMessageInTheme = client.userID === message.user?.id && !!myMessageTheme;
779
- const renderDateSeperator = isMessageWithStylesReadByAndDateSeparator(message) &&
780
- message.dateSeparator && <InlineDateSeparator date={message.dateSeparator} />;
781
- const renderMessage = (
782
- <Message
783
- goToMessage={goToMessage}
784
- groupStyles={isMessageWithStylesReadByAndDateSeparator(message) ? message.groupStyles : []}
785
- isTargetedMessage={highlightedMessageId === message.id}
786
- lastReceivedId={
787
- lastReceivedId === message.id || message.quoted_message_id ? lastReceivedId : undefined
788
- }
789
- message={message}
790
- onThreadSelect={onThreadSelect}
791
- showUnreadUnderlay={showUnreadUnderlay}
792
- style={[messageContainer]}
793
- threadList={threadList}
794
- />
795
- );
765
+ const createdAtTimestamp = message.created_at && new Date(message.created_at).getTime();
766
+ const lastReadTimestamp = channelUnreadState?.last_read.getTime();
767
+ const isNewestMessage = index === 0;
768
+ const isLastReadMessage =
769
+ channelUnreadState?.last_read_message_id === message.id ||
770
+ (!channelUnreadState?.unread_messages && createdAtTimestamp === lastReadTimestamp);
771
+
772
+ const showUnreadSeparator =
773
+ isLastReadMessage &&
774
+ !isNewestMessage &&
775
+ // The `channelUnreadState?.first_unread_message_id` is here for sent messages unread label
776
+ (!!channelUnreadState?.first_unread_message_id || !!channelUnreadState?.unread_messages);
777
+
778
+ const showUnreadUnderlay = !!shouldShowUnreadUnderlay && showUnreadSeparator;
779
+
780
+ const wrapMessageInTheme = client.userID === message.user?.id && !!myMessageTheme;
781
+ const renderDateSeperator = isMessageWithStylesReadByAndDateSeparator(message) &&
782
+ message.dateSeparator && <InlineDateSeparator date={message.dateSeparator} />;
783
+ const renderMessage = (
784
+ <Message
785
+ goToMessage={goToMessage}
786
+ groupStyles={
787
+ isMessageWithStylesReadByAndDateSeparator(message) ? message.groupStyles : []
788
+ }
789
+ isTargetedMessage={highlightedMessageId === message.id}
790
+ lastReceivedId={
791
+ lastReceivedId === message.id || message.quoted_message_id ? lastReceivedId : undefined
792
+ }
793
+ message={message}
794
+ onThreadSelect={onThreadSelect}
795
+ showUnreadUnderlay={showUnreadUnderlay}
796
+ style={[messageContainer]}
797
+ threadList={threadList}
798
+ />
799
+ );
796
800
 
797
- return (
798
- <View
799
- style={[shouldApplyAndroidWorkaround ? styles.invertAndroid : undefined]}
800
- testID={`message-list-item-${index}`}
801
- >
802
- {message.type === 'system' ? (
803
- <MessageSystem
804
- message={message}
805
- style={[{ paddingHorizontal: screenPadding }, messageContainer]}
806
- />
807
- ) : wrapMessageInTheme ? (
808
- <ThemeProvider mergedStyle={modifiedTheme}>
801
+ return (
802
+ <View
803
+ style={[shouldApplyAndroidWorkaround ? styles.invertAndroid : undefined]}
804
+ testID={`message-list-item-${index}`}
805
+ >
806
+ {message.type === 'system' ? (
807
+ <MessageSystem
808
+ message={message}
809
+ style={[{ paddingHorizontal: screenPadding }, messageContainer]}
810
+ />
811
+ ) : wrapMessageInTheme ? (
812
+ <ThemeProvider mergedStyle={modifiedTheme}>
813
+ <View testID={`message-list-item-${index}`}>
814
+ {renderDateSeperator}
815
+ {renderMessage}
816
+ </View>
817
+ </ThemeProvider>
818
+ ) : (
809
819
  <View testID={`message-list-item-${index}`}>
810
820
  {renderDateSeperator}
811
821
  {renderMessage}
812
822
  </View>
813
- </ThemeProvider>
814
- ) : (
815
- <View testID={`message-list-item-${index}`}>
816
- {renderDateSeperator}
817
- {renderMessage}
818
- </View>
819
- )}
820
- {showUnreadUnderlay && <InlineUnreadIndicator />}
821
- </View>
822
- );
823
- };
823
+ )}
824
+ {showUnreadUnderlay && <InlineUnreadIndicator />}
825
+ </View>
826
+ );
827
+ },
828
+ [
829
+ InlineDateSeparator,
830
+ InlineUnreadIndicator,
831
+ Message,
832
+ MessageSystem,
833
+ channel,
834
+ channelUnreadState?.first_unread_message_id,
835
+ channelUnreadState?.last_read,
836
+ channelUnreadState?.last_read_message_id,
837
+ channelUnreadState?.unread_messages,
838
+ client.userID,
839
+ goToMessage,
840
+ highlightedMessageId,
841
+ lastReceivedId,
842
+ messageContainer,
843
+ modifiedTheme,
844
+ myMessageTheme,
845
+ onThreadSelect,
846
+ screenPadding,
847
+ shouldApplyAndroidWorkaround,
848
+ shouldShowUnreadUnderlay,
849
+ threadList,
850
+ ],
851
+ );
824
852
 
825
853
  /**
826
854
  * We are keeping full control on message pagination, and not relying on react-native for it.
@@ -845,7 +873,7 @@ const MessageListWithContext = <
845
873
  * 2. Ensures that we call `loadMoreRecent`, once per content length
846
874
  * 3. If the call to `loadMore` is in progress, we wait for it to finish to make sure scroll doesn't jump.
847
875
  */
848
- const maybeCallOnStartReached = async () => {
876
+ const maybeCallOnStartReached = useStableCallback(async () => {
849
877
  // If onStartReached has already been called for given data length, then ignore.
850
878
  if (
851
879
  processedMessageList?.length &&
@@ -882,14 +910,14 @@ const MessageListWithContext = <
882
910
  )
883
911
  .then(callback)
884
912
  .catch(onError);
885
- };
913
+ });
886
914
 
887
915
  /**
888
916
  * 1. Makes a call to `loadMore` function, which queries more older messages.
889
917
  * 2. Ensures that we call `loadMore`, once per content length
890
918
  * 3. If the call to `loadMoreRecent` is in progress, we wait for it to finish to make sure scroll doesn't jump.
891
919
  */
892
- const maybeCallOnEndReached = async () => {
920
+ const maybeCallOnEndReached = useStableCallback(async () => {
893
921
  // If onEndReached has already been called for given messageList length, then ignore.
894
922
  if (processedMessageList?.length && onEndReachedTracker.current[processedMessageList.length]) {
895
923
  return;
@@ -918,9 +946,9 @@ const MessageListWithContext = <
918
946
  onEndReachedInPromise.current = (threadList ? loadMoreThread() : loadMore())
919
947
  .then(callback)
920
948
  .catch(onError);
921
- };
949
+ });
922
950
 
923
- const onUserScrollEvent: NonNullable<ScrollViewProps['onScroll']> = (event) => {
951
+ const onUserScrollEvent: NonNullable<ScrollViewProps['onScroll']> = useStableCallback((event) => {
924
952
  const nativeEvent = event.nativeEvent;
925
953
  clearTimeout(onScrollEventTimeoutRef.current);
926
954
  const offset = nativeEvent.contentOffset.y;
@@ -941,9 +969,9 @@ const MessageListWithContext = <
941
969
  if (isScrollAtEnd) {
942
970
  maybeCallOnEndReached();
943
971
  }
944
- };
972
+ });
945
973
 
946
- const handleScroll: ScrollViewProps['onScroll'] = (event) => {
974
+ const handleScroll: ScrollViewProps['onScroll'] = useStableCallback((event) => {
947
975
  const messageListHasMessages = processedMessageList.length > 0;
948
976
  const offset = event.nativeEvent.contentOffset.y;
949
977
  // Show scrollToBottom button once scroll position goes beyond 150.
@@ -965,9 +993,9 @@ const MessageListWithContext = <
965
993
  if (onListScroll) {
966
994
  onListScroll(event);
967
995
  }
968
- };
996
+ });
969
997
 
970
- const goToNewMessages = async () => {
998
+ const goToNewMessages = useStableCallback(async () => {
971
999
  const isNotLatestSet = channel.state.messages !== channel.state.latestMessages;
972
1000
 
973
1001
  if (isNotLatestSet) {
@@ -988,7 +1016,7 @@ const MessageListWithContext = <
988
1016
  await markRead({
989
1017
  updateChannelUnreadState: false,
990
1018
  });
991
- };
1019
+ });
992
1020
 
993
1021
  const scrollToIndexFailedRetryCountRef = useRef<number>(0);
994
1022
  const failScrollTimeoutId = useRef<ReturnType<typeof setTimeout>>(undefined);
@@ -1089,35 +1117,35 @@ const MessageListWithContext = <
1089
1117
  threadList,
1090
1118
  ]);
1091
1119
 
1092
- const dismissImagePicker = () => {
1120
+ const dismissImagePicker = useStableCallback(() => {
1093
1121
  if (selectedPicker) {
1094
1122
  setSelectedPicker(undefined);
1095
1123
  closePicker();
1096
1124
  }
1097
- };
1125
+ });
1098
1126
 
1099
- const onScrollBeginDrag: ScrollViewProps['onScrollBeginDrag'] = (event) => {
1127
+ const onScrollBeginDrag: ScrollViewProps['onScrollBeginDrag'] = useStableCallback((event) => {
1100
1128
  !hasMoved && selectedPicker && setHasMoved(true);
1101
1129
  onUserScrollEvent(event);
1102
- };
1130
+ });
1103
1131
 
1104
- const onScrollEndDrag: ScrollViewProps['onScrollEndDrag'] = (event) => {
1132
+ const onScrollEndDrag: ScrollViewProps['onScrollEndDrag'] = useStableCallback((event) => {
1105
1133
  hasMoved && selectedPicker && setHasMoved(false);
1106
1134
  onUserScrollEvent(event);
1107
- };
1135
+ });
1108
1136
 
1109
- const refCallback = (ref: FlatListType<MessageType<StreamChatGenerics>>) => {
1137
+ const refCallback = useStableCallback((ref: FlatListType<MessageType<StreamChatGenerics>>) => {
1110
1138
  flatListRef.current = ref;
1111
1139
 
1112
1140
  if (setFlatListRef) {
1113
1141
  setFlatListRef(ref);
1114
1142
  }
1115
- };
1143
+ });
1116
1144
 
1117
- const onUnreadNotificationClose = async () => {
1145
+ const onUnreadNotificationClose = useStableCallback(async () => {
1118
1146
  await markRead();
1119
1147
  setIsUnreadNotificationOpen(false);
1120
- };
1148
+ });
1121
1149
 
1122
1150
  const debugRef = useDebugContext();
1123
1151
 
@@ -1178,6 +1206,25 @@ const MessageListWithContext = <
1178
1206
  additionalFlatListPropsExcludingStyle = rest;
1179
1207
  }
1180
1208
 
1209
+ const flatListStyle = useMemo(
1210
+ () => [
1211
+ styles.listContainer,
1212
+ listContainer,
1213
+ additionalFlatListProps?.style,
1214
+ shouldApplyAndroidWorkaround ? styles.invertAndroid : undefined,
1215
+ ],
1216
+ [additionalFlatListProps?.style, listContainer, shouldApplyAndroidWorkaround],
1217
+ );
1218
+
1219
+ const flatListContentContainerStyle = useMemo(
1220
+ () => [
1221
+ styles.contentContainer,
1222
+ additionalFlatListProps?.contentContainerStyle,
1223
+ contentContainer,
1224
+ ],
1225
+ [additionalFlatListProps?.contentContainerStyle, contentContainer],
1226
+ );
1227
+
1181
1228
  if (!FlatList) {
1182
1229
  return null;
1183
1230
  }
@@ -1202,11 +1249,7 @@ const MessageListWithContext = <
1202
1249
  </View>
1203
1250
  ) : (
1204
1251
  <FlatList
1205
- contentContainerStyle={[
1206
- styles.contentContainer,
1207
- additionalFlatListProps?.contentContainerStyle,
1208
- contentContainer,
1209
- ]}
1252
+ contentContainerStyle={flatListContentContainerStyle}
1210
1253
  /** Disables the MessageList UI. Which means, message actions, reactions won't work. */
1211
1254
  data={processedMessageList}
1212
1255
  extraData={disabled}
@@ -1222,10 +1265,7 @@ const MessageListWithContext = <
1222
1265
  minIndexForVisible = 1 means that beyond the item at index 1 we will not change the position on list updates,
1223
1266
  however it is not used when autoscrollToTopThreshold = 10.
1224
1267
  */
1225
- maintainVisibleContentPosition={{
1226
- autoscrollToTopThreshold: autoscrollToRecent ? 10 : undefined,
1227
- minIndexForVisible: 1,
1228
- }}
1268
+ maintainVisibleContentPosition={maintainVisibleContentPosition}
1229
1269
  maxToRenderPerBatch={30}
1230
1270
  onMomentumScrollEnd={onUserScrollEvent}
1231
1271
  onScroll={handleScroll}
@@ -1238,12 +1278,7 @@ const MessageListWithContext = <
1238
1278
  renderItem={renderItem}
1239
1279
  scrollEnabled={overlay === 'none'}
1240
1280
  showsVerticalScrollIndicator={!shouldApplyAndroidWorkaround}
1241
- style={[
1242
- styles.listContainer,
1243
- listContainer,
1244
- additionalFlatListProps?.style,
1245
- shouldApplyAndroidWorkaround ? styles.invertAndroid : undefined,
1246
- ]}
1281
+ style={flatListStyle}
1247
1282
  testID='message-flat-list'
1248
1283
  viewabilityConfig={flatListViewabilityConfig}
1249
1284
  {...additionalFlatListPropsExcludingStyle}
@@ -1,3 +1,5 @@
1
+ import { useMemo } from 'react';
2
+
1
3
  import type { ChannelState, MessageResponse } from 'stream-chat';
2
4
 
3
5
  import { useLastReadData } from './useLastReadData';
@@ -44,6 +46,29 @@ export const isMessageWithStylesReadByAndDateSeparator = <
44
46
  ): message is MessagesWithStylesReadByAndDateSeparator<StreamChatGenerics> =>
45
47
  (message as MessagesWithStylesReadByAndDateSeparator<StreamChatGenerics>).readBy !== undefined;
46
48
 
49
+ export const shouldIncludeMessageInList = <
50
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
51
+ >(
52
+ message: MessageType<StreamChatGenerics>,
53
+ options: { deletedMessagesVisibilityType?: DeletedMessagesVisibilityType; userId?: string },
54
+ ) => {
55
+ const { deletedMessagesVisibilityType, userId } = options;
56
+ const isMessageTypeDeleted = message.type === 'deleted';
57
+ switch (deletedMessagesVisibilityType) {
58
+ case 'sender':
59
+ return !isMessageTypeDeleted || message.user?.id === userId;
60
+
61
+ case 'receiver':
62
+ return !isMessageTypeDeleted || message.user?.id !== userId;
63
+
64
+ case 'never':
65
+ return !isMessageTypeDeleted;
66
+
67
+ default:
68
+ return !!message;
69
+ }
70
+ };
71
+
47
72
  export const useMessageList = <
48
73
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
49
74
  >(
@@ -63,51 +88,57 @@ export const useMessageList = <
63
88
  ? undefined
64
89
  : read;
65
90
 
66
- const dateSeparators = getDateSeparators<StreamChatGenerics>({
67
- deletedMessagesVisibilityType,
68
- hideDateSeparators,
69
- messages: messageList,
70
- userId: client.userID,
71
- });
72
-
73
- const messageGroupStyles = getMessagesGroupStyles<StreamChatGenerics>({
74
- dateSeparators,
75
- hideDateSeparators,
76
- maxTimeBetweenGroupedMessages,
77
- messages: messageList,
78
- noGroupByUser,
79
- userId: client.userID,
80
- });
81
-
82
91
  const readData = useLastReadData({
83
92
  messages: messageList,
84
93
  read: readList,
85
94
  userID: client.userID,
86
95
  });
87
96
 
88
- const messagesWithStylesReadByAndDateSeparator = messageList
89
- .filter((msg) => {
90
- const isMessageTypeDeleted = msg.type === 'deleted';
91
- if (deletedMessagesVisibilityType === 'sender') {
92
- return !isMessageTypeDeleted || msg.user?.id === client.userID;
93
- } else if (deletedMessagesVisibilityType === 'receiver') {
94
- return !isMessageTypeDeleted || msg.user?.id !== client.userID;
95
- } else if (deletedMessagesVisibilityType === 'never') {
96
- return !isMessageTypeDeleted;
97
- } else {
98
- return msg;
97
+ const processedMessageList = useMemo<MessageType<StreamChatGenerics>[]>(() => {
98
+ const dateSeparators = getDateSeparators({
99
+ deletedMessagesVisibilityType,
100
+ hideDateSeparators,
101
+ messages: messageList,
102
+ userId: client.userID,
103
+ });
104
+
105
+ const messageGroupStyles = getMessagesGroupStyles({
106
+ dateSeparators,
107
+ hideDateSeparators,
108
+ maxTimeBetweenGroupedMessages,
109
+ messages: messageList,
110
+ noGroupByUser,
111
+ userId: client.userID,
112
+ });
113
+
114
+ const newMessageList = [];
115
+ for (const message of messageList) {
116
+ if (
117
+ shouldIncludeMessageInList(message, {
118
+ deletedMessagesVisibilityType,
119
+ userId: client.userID,
120
+ })
121
+ ) {
122
+ const messageId = message.id;
123
+ newMessageList.unshift({
124
+ ...message,
125
+ dateSeparator: dateSeparators[messageId] || undefined,
126
+ groupStyles: messageGroupStyles[messageId] || ['single'],
127
+ readBy: messageId ? readData[messageId] || false : false,
128
+ });
99
129
  }
100
- })
101
- .map((msg) => ({
102
- ...msg,
103
- dateSeparator: dateSeparators[msg.id] || undefined,
104
- groupStyles: messageGroupStyles[msg.id] || ['single'],
105
- readBy: msg.id ? readData[msg.id] || false : false,
106
- }));
107
-
108
- const processedMessageList = [
109
- ...messagesWithStylesReadByAndDateSeparator,
110
- ].reverse() as MessageType<StreamChatGenerics>[];
130
+ }
131
+ return newMessageList;
132
+ }, [
133
+ client.userID,
134
+ deletedMessagesVisibilityType,
135
+ getMessagesGroupStyles,
136
+ hideDateSeparators,
137
+ maxTimeBetweenGroupedMessages,
138
+ messageList,
139
+ noGroupByUser,
140
+ readData,
141
+ ]);
111
142
 
112
143
  return {
113
144
  /** Messages enriched with dates/readby/groups and also reversed in order */