stream-chat-react-native-core 6.0.2-beta.1 → 6.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/commonjs/components/Channel/Channel.js +371 -279
- package/lib/commonjs/components/Channel/Channel.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useChannelDataState.js +8 -0
- package/lib/commonjs/components/Channel/hooks/useChannelDataState.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useCreateChannelContext.js +10 -1
- package/lib/commonjs/components/Channel/hooks/useCreateChannelContext.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js +4 -0
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useMessageListPagination.js +161 -69
- package/lib/commonjs/components/Channel/hooks/useMessageListPagination.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useTargetedMessage.js +10 -0
- package/lib/commonjs/components/Channel/hooks/useTargetedMessage.js.map +1 -1
- package/lib/commonjs/components/Chat/hooks/handleEventToSyncDB.js +81 -54
- package/lib/commonjs/components/Chat/hooks/handleEventToSyncDB.js.map +1 -1
- package/lib/commonjs/components/Message/Message.js +6 -0
- package/lib/commonjs/components/Message/Message.js.map +1 -1
- package/lib/commonjs/components/Message/hooks/useMessageActionHandlers.js +117 -79
- package/lib/commonjs/components/Message/hooks/useMessageActionHandlers.js.map +1 -1
- package/lib/commonjs/components/Message/hooks/useMessageActions.js +32 -14
- package/lib/commonjs/components/Message/hooks/useMessageActions.js.map +1 -1
- package/lib/commonjs/components/Message/utils/messageActions.js +4 -0
- package/lib/commonjs/components/Message/utils/messageActions.js.map +1 -1
- package/lib/commonjs/components/MessageList/InlineUnreadIndicator.js +19 -55
- package/lib/commonjs/components/MessageList/InlineUnreadIndicator.js.map +1 -1
- package/lib/commonjs/components/MessageList/MessageList.js +249 -211
- package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
- package/lib/commonjs/components/MessageList/UnreadMessagesNotification.js +148 -0
- package/lib/commonjs/components/MessageList/UnreadMessagesNotification.js.map +1 -0
- package/lib/commonjs/components/MessageMenu/MessageActionListItem.js.map +1 -1
- package/lib/commonjs/contexts/channelContext/ChannelContext.js.map +1 -1
- package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/commonjs/contexts/themeContext/utils/theme.js +7 -1
- package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/commonjs/i18n/en.json +2 -0
- package/lib/commonjs/i18n/es.json +2 -0
- package/lib/commonjs/i18n/fr.json +2 -0
- package/lib/commonjs/i18n/he.json +2 -0
- package/lib/commonjs/i18n/hi.json +2 -0
- package/lib/commonjs/i18n/it.json +2 -0
- package/lib/commonjs/i18n/ja.json +2 -0
- package/lib/commonjs/i18n/ko.json +2 -0
- package/lib/commonjs/i18n/nl.json +2 -0
- package/lib/commonjs/i18n/pt-br.json +2 -0
- package/lib/commonjs/i18n/ru.json +2 -0
- package/lib/commonjs/i18n/tr.json +2 -0
- package/lib/commonjs/icons/UnreadIndicator.js +30 -0
- package/lib/commonjs/icons/UnreadIndicator.js.map +1 -0
- package/lib/commonjs/icons/index.js +11 -0
- package/lib/commonjs/icons/index.js.map +1 -1
- package/lib/commonjs/store/SqliteClient.js +1 -1
- package/lib/commonjs/store/schema.js +1 -0
- package/lib/commonjs/store/schema.js.map +1 -1
- package/lib/commonjs/types/types.js.map +1 -1
- package/lib/commonjs/utils/utils.js +35 -1
- package/lib/commonjs/utils/utils.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Channel/Channel.js +371 -279
- package/lib/module/components/Channel/Channel.js.map +1 -1
- package/lib/module/components/Channel/hooks/useChannelDataState.js +8 -0
- package/lib/module/components/Channel/hooks/useChannelDataState.js.map +1 -1
- package/lib/module/components/Channel/hooks/useCreateChannelContext.js +10 -1
- package/lib/module/components/Channel/hooks/useCreateChannelContext.js.map +1 -1
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js +4 -0
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/module/components/Channel/hooks/useMessageListPagination.js +161 -69
- package/lib/module/components/Channel/hooks/useMessageListPagination.js.map +1 -1
- package/lib/module/components/Channel/hooks/useTargetedMessage.js +10 -0
- package/lib/module/components/Channel/hooks/useTargetedMessage.js.map +1 -1
- package/lib/module/components/Chat/hooks/handleEventToSyncDB.js +81 -54
- package/lib/module/components/Chat/hooks/handleEventToSyncDB.js.map +1 -1
- package/lib/module/components/Message/Message.js +6 -0
- package/lib/module/components/Message/Message.js.map +1 -1
- package/lib/module/components/Message/hooks/useMessageActionHandlers.js +117 -79
- package/lib/module/components/Message/hooks/useMessageActionHandlers.js.map +1 -1
- package/lib/module/components/Message/hooks/useMessageActions.js +32 -14
- package/lib/module/components/Message/hooks/useMessageActions.js.map +1 -1
- package/lib/module/components/Message/utils/messageActions.js +4 -0
- package/lib/module/components/Message/utils/messageActions.js.map +1 -1
- package/lib/module/components/MessageList/InlineUnreadIndicator.js +19 -55
- package/lib/module/components/MessageList/InlineUnreadIndicator.js.map +1 -1
- package/lib/module/components/MessageList/MessageList.js +249 -211
- package/lib/module/components/MessageList/MessageList.js.map +1 -1
- package/lib/module/components/MessageList/UnreadMessagesNotification.js +148 -0
- package/lib/module/components/MessageList/UnreadMessagesNotification.js.map +1 -0
- package/lib/module/components/MessageMenu/MessageActionListItem.js.map +1 -1
- package/lib/module/contexts/channelContext/ChannelContext.js.map +1 -1
- package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/module/contexts/themeContext/utils/theme.js +7 -1
- package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/module/i18n/en.json +2 -0
- package/lib/module/i18n/es.json +2 -0
- package/lib/module/i18n/fr.json +2 -0
- package/lib/module/i18n/he.json +2 -0
- package/lib/module/i18n/hi.json +2 -0
- package/lib/module/i18n/it.json +2 -0
- package/lib/module/i18n/ja.json +2 -0
- package/lib/module/i18n/ko.json +2 -0
- package/lib/module/i18n/nl.json +2 -0
- package/lib/module/i18n/pt-br.json +2 -0
- package/lib/module/i18n/ru.json +2 -0
- package/lib/module/i18n/tr.json +2 -0
- package/lib/module/icons/UnreadIndicator.js +30 -0
- package/lib/module/icons/UnreadIndicator.js.map +1 -0
- package/lib/module/icons/index.js +11 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/store/SqliteClient.js +1 -1
- package/lib/module/store/schema.js +1 -0
- package/lib/module/store/schema.js.map +1 -1
- package/lib/module/types/types.js.map +1 -1
- package/lib/module/utils/utils.js +35 -1
- package/lib/module/utils/utils.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/Channel/Channel.d.ts +15 -3
- package/lib/typescript/components/Channel/Channel.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useChannelDataState.d.ts +1 -0
- package/lib/typescript/components/Channel/hooks/useChannelDataState.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateChannelContext.d.ts +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateChannelContext.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts +4 -2
- package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useMessageListPagination.d.ts +4 -1
- package/lib/typescript/components/Channel/hooks/useMessageListPagination.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useTargetedMessage.d.ts +2 -1
- package/lib/typescript/components/Channel/hooks/useTargetedMessage.d.ts.map +1 -1
- package/lib/typescript/components/Chat/hooks/handleEventToSyncDB.d.ts.map +1 -1
- package/lib/typescript/components/Message/Message.d.ts +2 -1
- package/lib/typescript/components/Message/Message.d.ts.map +1 -1
- package/lib/typescript/components/Message/hooks/useMessageActionHandlers.d.ts +2 -1
- package/lib/typescript/components/Message/hooks/useMessageActionHandlers.d.ts.map +1 -1
- package/lib/typescript/components/Message/hooks/useMessageActions.d.ts +3 -2
- package/lib/typescript/components/Message/hooks/useMessageActions.d.ts.map +1 -1
- package/lib/typescript/components/Message/hooks/useMessageData.d.ts +1 -1
- package/lib/typescript/components/Message/utils/messageActions.d.ts +2 -1
- package/lib/typescript/components/Message/utils/messageActions.d.ts.map +1 -1
- package/lib/typescript/components/MessageList/InlineUnreadIndicator.d.ts.map +1 -1
- package/lib/typescript/components/MessageList/MessageList.d.ts +1 -1
- package/lib/typescript/components/MessageList/MessageList.d.ts.map +1 -1
- package/lib/typescript/components/MessageList/UnreadMessagesNotification.d.ts +13 -0
- package/lib/typescript/components/MessageList/UnreadMessagesNotification.d.ts.map +1 -0
- package/lib/typescript/components/MessageMenu/MessageActionListItem.d.ts +2 -2
- package/lib/typescript/components/MessageMenu/MessageActionListItem.d.ts.map +1 -1
- package/lib/typescript/contexts/channelContext/ChannelContext.d.ts +25 -8
- package/lib/typescript/contexts/channelContext/ChannelContext.d.ts.map +1 -1
- package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +5 -0
- package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts.map +1 -1
- package/lib/typescript/contexts/themeContext/utils/theme.d.ts +6 -0
- package/lib/typescript/contexts/themeContext/utils/theme.d.ts.map +1 -1
- package/lib/typescript/i18n/en.json +2 -0
- package/lib/typescript/i18n/es.json +2 -0
- package/lib/typescript/i18n/fr.json +2 -0
- package/lib/typescript/i18n/he.json +2 -0
- package/lib/typescript/i18n/hi.json +2 -0
- package/lib/typescript/i18n/it.json +2 -0
- package/lib/typescript/i18n/ja.json +2 -0
- package/lib/typescript/i18n/ko.json +2 -0
- package/lib/typescript/i18n/nl.json +2 -0
- package/lib/typescript/i18n/pt-br.json +2 -0
- package/lib/typescript/i18n/ru.json +2 -0
- package/lib/typescript/i18n/tr.json +2 -0
- package/lib/typescript/icons/UnreadIndicator.d.ts +8 -0
- package/lib/typescript/icons/UnreadIndicator.d.ts.map +1 -0
- package/lib/typescript/icons/index.d.ts +1 -0
- package/lib/typescript/icons/index.d.ts.map +1 -1
- package/lib/typescript/store/mappers/mapStorableToChannel.d.ts +1 -1
- package/lib/typescript/store/schema.d.ts +1 -0
- package/lib/typescript/store/schema.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +2 -1
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/utils/i18n/Streami18n.d.ts +2 -0
- package/lib/typescript/utils/i18n/Streami18n.d.ts.map +1 -1
- package/lib/typescript/utils/utils.d.ts +21 -1
- package/lib/typescript/utils/utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Channel/Channel.tsx +101 -24
- package/src/components/Channel/__tests__/Channel.test.js +109 -58
- package/src/components/Channel/__tests__/ownCapabilities.test.js +26 -0
- package/src/components/Channel/__tests__/useMessageListPagination.test.js +234 -37
- package/src/components/Channel/hooks/useChannelDataState.ts +8 -0
- package/src/components/Channel/hooks/useCreateChannelContext.ts +11 -0
- package/src/components/Channel/hooks/useCreateMessagesContext.ts +4 -0
- package/src/components/Channel/hooks/useMessageListPagination.tsx +134 -64
- package/src/components/Channel/hooks/useTargetedMessage.ts +9 -2
- package/src/components/Chat/hooks/handleEventToSyncDB.ts +23 -1
- package/src/components/Message/Message.tsx +8 -0
- package/src/components/Message/hooks/useMessageActionHandlers.ts +54 -40
- package/src/components/Message/hooks/useMessageActions.tsx +31 -14
- package/src/components/Message/utils/messageActions.ts +6 -0
- package/src/components/MessageList/InlineUnreadIndicator.tsx +17 -26
- package/src/components/MessageList/MessageList.tsx +197 -231
- package/src/components/MessageList/UnreadMessagesNotification.tsx +107 -0
- package/src/components/MessageList/__tests__/MessageList.test.js +213 -0
- package/src/components/MessageMenu/MessageActionListItem.tsx +2 -1
- package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +669 -679
- package/src/contexts/channelContext/ChannelContext.tsx +35 -9
- package/src/contexts/messagesContext/MessagesContext.tsx +7 -2
- package/src/contexts/themeContext/utils/theme.ts +12 -0
- package/src/i18n/en.json +2 -0
- package/src/i18n/es.json +2 -0
- package/src/i18n/fr.json +2 -0
- package/src/i18n/he.json +2 -0
- package/src/i18n/hi.json +2 -0
- package/src/i18n/it.json +2 -0
- package/src/i18n/ja.json +2 -0
- package/src/i18n/ko.json +2 -0
- package/src/i18n/nl.json +2 -0
- package/src/i18n/pt-br.json +2 -0
- package/src/i18n/ru.json +2 -0
- package/src/i18n/tr.json +2 -0
- package/src/icons/UnreadIndicator.tsx +18 -0
- package/src/icons/index.ts +1 -0
- package/src/store/SqliteClient.ts +1 -1
- package/src/store/schema.ts +2 -0
- package/src/types/types.ts +5 -2
- package/src/utils/utils.ts +61 -1
- package/src/version.json +1 -1
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ScrollViewProps,
|
|
7
7
|
StyleSheet,
|
|
8
8
|
View,
|
|
9
|
+
ViewabilityConfig,
|
|
9
10
|
ViewToken,
|
|
10
11
|
} from 'react-native';
|
|
11
12
|
|
|
@@ -54,7 +55,9 @@ import { ThreadContextValue, useThreadContext } from '../../contexts/threadConte
|
|
|
54
55
|
|
|
55
56
|
import { DefaultStreamChatGenerics, FileTypes } from '../../types/types';
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
// This is just to make sure that the scrolling happens in a different task queue.
|
|
59
|
+
// TODO: Think if we really need this and strive to remove it if we can.
|
|
60
|
+
const WAIT_FOR_SCROLL_TIMEOUT = 0;
|
|
58
61
|
const MAX_RETRIES_AFTER_SCROLL_FAILURE = 10;
|
|
59
62
|
const styles = StyleSheet.create({
|
|
60
63
|
container: {
|
|
@@ -63,7 +66,6 @@ const styles = StyleSheet.create({
|
|
|
63
66
|
width: '100%',
|
|
64
67
|
},
|
|
65
68
|
contentContainer: {
|
|
66
|
-
flexGrow: 1,
|
|
67
69
|
/**
|
|
68
70
|
* paddingBottom is set to 4 to account for the default date
|
|
69
71
|
* header and inline indicator alignment. The top margin is 8
|
|
@@ -99,7 +101,7 @@ const keyExtractor = <
|
|
|
99
101
|
return Date.now().toString();
|
|
100
102
|
};
|
|
101
103
|
|
|
102
|
-
const flatListViewabilityConfig = {
|
|
104
|
+
const flatListViewabilityConfig: ViewabilityConfig = {
|
|
103
105
|
viewAreaCoveragePercentThreshold: 1,
|
|
104
106
|
};
|
|
105
107
|
|
|
@@ -109,9 +111,11 @@ type MessageListPropsWithContext<
|
|
|
109
111
|
Pick<
|
|
110
112
|
ChannelContextValue<StreamChatGenerics>,
|
|
111
113
|
| 'channel'
|
|
114
|
+
| 'channelUnreadState'
|
|
112
115
|
| 'disabled'
|
|
113
116
|
| 'EmptyStateIndicator'
|
|
114
117
|
| 'hideStickyDateHeader'
|
|
118
|
+
| 'highlightedMessageId'
|
|
115
119
|
| 'loadChannelAroundMessage'
|
|
116
120
|
| 'loading'
|
|
117
121
|
| 'LoadingIndicator'
|
|
@@ -133,7 +137,6 @@ type MessageListPropsWithContext<
|
|
|
133
137
|
| 'DateHeader'
|
|
134
138
|
| 'disableTypingIndicator'
|
|
135
139
|
| 'FlatList'
|
|
136
|
-
| 'initialScrollToFirstUnreadMessage'
|
|
137
140
|
| 'InlineDateSeparator'
|
|
138
141
|
| 'InlineUnreadIndicator'
|
|
139
142
|
| 'legacyImageViewerSwipeBehaviour'
|
|
@@ -144,6 +147,7 @@ type MessageListPropsWithContext<
|
|
|
144
147
|
| 'shouldShowUnreadUnderlay'
|
|
145
148
|
| 'TypingIndicator'
|
|
146
149
|
| 'TypingIndicatorContainer'
|
|
150
|
+
| 'UnreadMessagesNotification'
|
|
147
151
|
> &
|
|
148
152
|
Pick<
|
|
149
153
|
ThreadContextValue<StreamChatGenerics>,
|
|
@@ -228,6 +232,7 @@ const MessageListWithContext = <
|
|
|
228
232
|
const {
|
|
229
233
|
additionalFlatListProps,
|
|
230
234
|
channel,
|
|
235
|
+
channelUnreadState,
|
|
231
236
|
client,
|
|
232
237
|
closePicker,
|
|
233
238
|
DateHeader,
|
|
@@ -238,7 +243,7 @@ const MessageListWithContext = <
|
|
|
238
243
|
FooterComponent = InlineLoadingMoreIndicator,
|
|
239
244
|
HeaderComponent = LoadingMoreRecentIndicator,
|
|
240
245
|
hideStickyDateHeader,
|
|
241
|
-
|
|
246
|
+
highlightedMessageId,
|
|
242
247
|
InlineDateSeparator,
|
|
243
248
|
InlineUnreadIndicator,
|
|
244
249
|
inverted = true,
|
|
@@ -275,8 +280,9 @@ const MessageListWithContext = <
|
|
|
275
280
|
threadList = false,
|
|
276
281
|
TypingIndicator,
|
|
277
282
|
TypingIndicatorContainer,
|
|
283
|
+
UnreadMessagesNotification,
|
|
278
284
|
} = props;
|
|
279
|
-
|
|
285
|
+
const [isUnreadNotificationOpen, setIsUnreadNotificationOpen] = useState<boolean>(false);
|
|
280
286
|
const { theme } = useTheme();
|
|
281
287
|
|
|
282
288
|
const {
|
|
@@ -333,12 +339,6 @@ const MessageListWithContext = <
|
|
|
333
339
|
|
|
334
340
|
const flatListRef = useRef<FlatListType<MessageType<StreamChatGenerics>> | null>(null);
|
|
335
341
|
|
|
336
|
-
/**
|
|
337
|
-
* Flag to track if the initial scroll has been set
|
|
338
|
-
* If the prop `initialScrollToFirstUnreadMessage` was enabled, then we scroll to the unread msg and set it to true
|
|
339
|
-
* If not, the default offset of 0 for flatList means that it has been set already
|
|
340
|
-
*/
|
|
341
|
-
const [isInitialScrollDone, setInitialScrollDone] = useState(!initialScrollToFirstUnreadMessage);
|
|
342
342
|
const channelResyncScrollSet = useRef<boolean>(true);
|
|
343
343
|
|
|
344
344
|
/**
|
|
@@ -346,11 +346,6 @@ const MessageListWithContext = <
|
|
|
346
346
|
*/
|
|
347
347
|
const scrollToDebounceTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
|
348
348
|
|
|
349
|
-
/**
|
|
350
|
-
* The timeout id used to lazier load the initial scroll set flag
|
|
351
|
-
*/
|
|
352
|
-
const initialScrollSettingTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
|
353
|
-
|
|
354
349
|
/**
|
|
355
350
|
* The timeout id used to temporarily load the initial scroll set flag
|
|
356
351
|
*/
|
|
@@ -375,11 +370,18 @@ const MessageListWithContext = <
|
|
|
375
370
|
channelRef.current = channel;
|
|
376
371
|
|
|
377
372
|
const updateStickyHeaderDateIfNeeded = (viewableItems: ViewToken[]) => {
|
|
378
|
-
if (viewableItems.length)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
};
|
|
373
|
+
if (!viewableItems.length) return;
|
|
374
|
+
|
|
375
|
+
const lastItem = viewableItems[viewableItems.length - 1];
|
|
382
376
|
|
|
377
|
+
if (lastItem) {
|
|
378
|
+
if (
|
|
379
|
+
!channel.state.messagePagination.hasPrev &&
|
|
380
|
+
processedMessageList[processedMessageList.length - 1].id === lastItem.item.id
|
|
381
|
+
) {
|
|
382
|
+
setStickyHeaderDate(undefined);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
383
385
|
const isMessageTypeDeleted = lastItem.item.type === 'deleted';
|
|
384
386
|
|
|
385
387
|
if (
|
|
@@ -395,32 +397,60 @@ const MessageListWithContext = <
|
|
|
395
397
|
};
|
|
396
398
|
|
|
397
399
|
/**
|
|
398
|
-
*
|
|
399
|
-
* Thus useRef.
|
|
400
|
+
* This function should show or hide the unread indicator depending on the
|
|
400
401
|
*/
|
|
401
|
-
const
|
|
402
|
-
(
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
402
|
+
const updateStickyUnreadIndicator = (viewableItems: ViewToken[]) => {
|
|
403
|
+
if (!viewableItems.length) {
|
|
404
|
+
setIsUnreadNotificationOpen(false);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (selectedPicker === 'images') {
|
|
409
|
+
setIsUnreadNotificationOpen(false);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const lastItem = viewableItems[viewableItems.length - 1];
|
|
414
|
+
|
|
415
|
+
if (lastItem) {
|
|
416
|
+
const lastItemCreatedAt = lastItem.item.created_at;
|
|
417
|
+
|
|
418
|
+
const unreadIndicatorDate = channelUnreadState?.last_read.getTime();
|
|
419
|
+
const lastItemDate = lastItemCreatedAt.getTime();
|
|
420
|
+
|
|
411
421
|
if (
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
viewableItems?.length >= messageListLengthBeforeUpdate.current
|
|
422
|
+
!channel.state.messagePagination.hasPrev &&
|
|
423
|
+
processedMessageList[processedMessageList.length - 1].id === lastItem.item.id
|
|
415
424
|
) {
|
|
416
|
-
|
|
425
|
+
setIsUnreadNotificationOpen(false);
|
|
426
|
+
return;
|
|
417
427
|
}
|
|
418
428
|
|
|
419
|
-
if (
|
|
420
|
-
|
|
429
|
+
if (unreadIndicatorDate && lastItemDate > unreadIndicatorDate) {
|
|
430
|
+
setIsUnreadNotificationOpen(true);
|
|
431
|
+
} else {
|
|
432
|
+
setIsUnreadNotificationOpen(false);
|
|
421
433
|
}
|
|
422
|
-
}
|
|
423
|
-
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* FlatList doesn't accept changeable function for onViewableItemsChanged prop.
|
|
439
|
+
* Thus useRef.
|
|
440
|
+
*/
|
|
441
|
+
const onViewableItemsChanged = ({
|
|
442
|
+
viewableItems,
|
|
443
|
+
}: {
|
|
444
|
+
viewableItems: ViewToken[] | undefined;
|
|
445
|
+
}) => {
|
|
446
|
+
if (!viewableItems) {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
if (!hideStickyDateHeader) {
|
|
450
|
+
updateStickyHeaderDateIfNeeded(viewableItems);
|
|
451
|
+
}
|
|
452
|
+
updateStickyUnreadIndicator(viewableItems);
|
|
453
|
+
};
|
|
424
454
|
|
|
425
455
|
/**
|
|
426
456
|
* Resets the pagination trackers, doing so cancels currently scheduled loading more calls
|
|
@@ -440,40 +470,19 @@ const MessageListWithContext = <
|
|
|
440
470
|
* Effect to mark the channel as read when the user scrolls to the bottom of the message list.
|
|
441
471
|
*/
|
|
442
472
|
useEffect(() => {
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
/*
|
|
450
|
-
* In this case MessageList won't scroll to first unread message when opened, so we can mark
|
|
451
|
-
* the channel as read right after opening.
|
|
452
|
-
* */
|
|
453
|
-
return true;
|
|
454
|
-
} else {
|
|
455
|
-
/*
|
|
456
|
-
* In this case MessageList will be opened to first unread message.
|
|
457
|
-
* But if there are were not enough unread messages, so that scrollToBottom button was not shown
|
|
458
|
-
* then MessageList won't need to scroll up. So we can safely mark the channel as read right after opening.
|
|
459
|
-
*
|
|
460
|
-
* NOTE: we must ensure that initial scroll is done, otherwise we do not wait till the unread scroll is finished
|
|
461
|
-
* */
|
|
462
|
-
if (scrollToBottomButtonVisible) return false;
|
|
463
|
-
/* if scrollToBottom button was not visible, wait till
|
|
464
|
-
* - initial scroll is done (indicates that if scrolling to index was needed it was triggered)
|
|
465
|
-
* */
|
|
466
|
-
return isInitialScrollDone;
|
|
467
|
-
}
|
|
473
|
+
const listener: ReturnType<typeof channel.on> = channel.on('message.new', (event) => {
|
|
474
|
+
const newMessageToCurrentChannel = event.cid === channel.cid;
|
|
475
|
+
const mainChannelUpdated = !event.message?.parent_id || event.message?.show_in_channel;
|
|
476
|
+
|
|
477
|
+
if (newMessageToCurrentChannel && mainChannelUpdated && !scrollToBottomButtonVisible) {
|
|
478
|
+
markRead();
|
|
468
479
|
}
|
|
469
|
-
|
|
470
|
-
};
|
|
480
|
+
});
|
|
471
481
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
}, [loading, scrollToBottomButtonVisible, isInitialScrollDone]);
|
|
482
|
+
return () => {
|
|
483
|
+
listener?.unsubscribe();
|
|
484
|
+
};
|
|
485
|
+
}, [channel, markRead, scrollToBottomButtonVisible]);
|
|
477
486
|
|
|
478
487
|
useEffect(() => {
|
|
479
488
|
const lastReceivedMessage = getLastReceivedMessage(processedMessageList);
|
|
@@ -487,6 +496,7 @@ const MessageListWithContext = <
|
|
|
487
496
|
if (!client || !channel || rawMessageList.length === 0) {
|
|
488
497
|
return;
|
|
489
498
|
}
|
|
499
|
+
|
|
490
500
|
/**
|
|
491
501
|
* Condition to check if a message is removed from MessageList.
|
|
492
502
|
* Eg: This would happen when giphy search is cancelled, etc.
|
|
@@ -508,7 +518,7 @@ const MessageListWithContext = <
|
|
|
508
518
|
flatListRef.current?.scrollToOffset({
|
|
509
519
|
offset: 0,
|
|
510
520
|
});
|
|
511
|
-
},
|
|
521
|
+
}, WAIT_FOR_SCROLL_TIMEOUT);
|
|
512
522
|
setTimeout(() => {
|
|
513
523
|
channelResyncScrollSet.current = true;
|
|
514
524
|
if (channel.countUnread() > 0) {
|
|
@@ -518,10 +528,9 @@ const MessageListWithContext = <
|
|
|
518
528
|
}
|
|
519
529
|
};
|
|
520
530
|
|
|
531
|
+
// TODO: Think about if this is really needed?
|
|
521
532
|
if (threadList) {
|
|
522
533
|
scrollToBottomIfNeeded();
|
|
523
|
-
} else {
|
|
524
|
-
setScrollToBottomButtonVisible(false);
|
|
525
534
|
}
|
|
526
535
|
|
|
527
536
|
messageListLengthBeforeUpdate.current = messageListLengthAfterUpdate;
|
|
@@ -566,12 +575,74 @@ const MessageListWithContext = <
|
|
|
566
575
|
animated: true,
|
|
567
576
|
offset: 0,
|
|
568
577
|
});
|
|
569
|
-
},
|
|
578
|
+
}, WAIT_FOR_SCROLL_TIMEOUT); // flatlist might take a bit to update, so a small delay is needed
|
|
570
579
|
}
|
|
571
580
|
}
|
|
572
581
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
573
582
|
}, [rawMessageList, threadList]);
|
|
574
583
|
|
|
584
|
+
const goToMessage = async (messageId: string) => {
|
|
585
|
+
const indexOfParentInMessageList = processedMessageList.findIndex(
|
|
586
|
+
(message) => message?.id === messageId,
|
|
587
|
+
);
|
|
588
|
+
try {
|
|
589
|
+
if (indexOfParentInMessageList === -1) {
|
|
590
|
+
await loadChannelAroundMessage({ messageId });
|
|
591
|
+
return;
|
|
592
|
+
} else {
|
|
593
|
+
if (!flatListRef.current) return;
|
|
594
|
+
clearTimeout(failScrollTimeoutId.current);
|
|
595
|
+
scrollToIndexFailedRetryCountRef.current = 0;
|
|
596
|
+
// keep track of this messageId, so that we dont scroll to again in useEffect for targeted message change
|
|
597
|
+
messageIdLastScrolledToRef.current = messageId;
|
|
598
|
+
setTargetedMessage(messageId);
|
|
599
|
+
// now scroll to it with animated=true
|
|
600
|
+
flatListRef.current.scrollToIndex({
|
|
601
|
+
animated: true,
|
|
602
|
+
index: indexOfParentInMessageList,
|
|
603
|
+
viewPosition: 0.5, // try to place message in the center of the screen
|
|
604
|
+
});
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
} catch (e) {
|
|
608
|
+
console.warn('Error while scrolling to message', e);
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Check if a messageId needs to be scrolled to after list loads, and scroll to it
|
|
614
|
+
* Note: This effect fires on every list change with a small debounce so that scrolling isnt abrupted by an immediate rerender
|
|
615
|
+
*/
|
|
616
|
+
useEffect(() => {
|
|
617
|
+
if (!targetedMessage) return;
|
|
618
|
+
scrollToDebounceTimeoutRef.current = setTimeout(async () => {
|
|
619
|
+
const indexOfParentInMessageList = processedMessageList.findIndex(
|
|
620
|
+
(message) => message?.id === targetedMessage,
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
// the message we want to scroll to has not been loaded in the state yet
|
|
624
|
+
if (indexOfParentInMessageList === -1) {
|
|
625
|
+
await loadChannelAroundMessage({ messageId: targetedMessage, setTargetedMessage });
|
|
626
|
+
} else {
|
|
627
|
+
if (!flatListRef.current) return;
|
|
628
|
+
// By a fresh scroll we should clear the retries for the previous failed scroll
|
|
629
|
+
clearTimeout(scrollToDebounceTimeoutRef.current);
|
|
630
|
+
clearTimeout(failScrollTimeoutId.current);
|
|
631
|
+
// reset the retry count
|
|
632
|
+
scrollToIndexFailedRetryCountRef.current = 0;
|
|
633
|
+
// now scroll to it
|
|
634
|
+
flatListRef.current.scrollToIndex({
|
|
635
|
+
animated: true,
|
|
636
|
+
index: indexOfParentInMessageList,
|
|
637
|
+
viewPosition: 0.5, // try to place message in the center of the screen
|
|
638
|
+
});
|
|
639
|
+
setTargetedMessage(undefined);
|
|
640
|
+
}
|
|
641
|
+
}, WAIT_FOR_SCROLL_TIMEOUT);
|
|
642
|
+
|
|
643
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
644
|
+
}, [targetedMessage]);
|
|
645
|
+
|
|
575
646
|
// TODO: do not apply on RN 0.73 and above
|
|
576
647
|
const shouldApplyAndroidWorkaround = inverted && Platform.OS === 'android';
|
|
577
648
|
|
|
@@ -585,53 +656,20 @@ const MessageListWithContext = <
|
|
|
585
656
|
if (!channel || channel.disconnected || (!channel.initialized && !channel.offlineMode))
|
|
586
657
|
return null;
|
|
587
658
|
|
|
588
|
-
const
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
);
|
|
659
|
+
const createdAtTimestamp = message.created_at && new Date(message.created_at).getTime();
|
|
660
|
+
const lastReadTimestamp = channelUnreadState?.last_read.getTime();
|
|
661
|
+
const isNewestMessage = index === 0;
|
|
662
|
+
const isLastReadMessage =
|
|
663
|
+
channelUnreadState?.last_read_message_id === message.id ||
|
|
664
|
+
(!channelUnreadState?.unread_messages && createdAtTimestamp === lastReadTimestamp);
|
|
595
665
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
) {
|
|
602
|
-
return messageArrayIndex <= unreadCount - channel.state.latestMessages.length - 1;
|
|
603
|
-
}
|
|
604
|
-
// The `msg` can be undefined here, since `messageArrayIndex` can be out of bounds hence we add a check for `msg`.
|
|
605
|
-
else if (lastRead && msg?.created_at) {
|
|
606
|
-
return lastRead < msg.created_at;
|
|
607
|
-
}
|
|
608
|
-
return false;
|
|
609
|
-
} else {
|
|
610
|
-
return messageArrayIndex <= unreadCount - 1;
|
|
611
|
-
}
|
|
612
|
-
}
|
|
666
|
+
const showUnreadSeparator =
|
|
667
|
+
isLastReadMessage &&
|
|
668
|
+
!isNewestMessage &&
|
|
669
|
+
// The `channelUnreadState?.first_unread_message_id` is here for sent messages unread label
|
|
670
|
+
(!!channelUnreadState?.first_unread_message_id || !!channelUnreadState?.unread_messages);
|
|
613
671
|
|
|
614
|
-
const
|
|
615
|
-
const showUnreadUnderlay =
|
|
616
|
-
!!shouldShowUnreadUnderlay &&
|
|
617
|
-
!channel.muteStatus().muted &&
|
|
618
|
-
isCurrentMessageUnread &&
|
|
619
|
-
scrollToBottomButtonVisible;
|
|
620
|
-
const insertInlineUnreadIndicator = showUnreadUnderlay && !isMessageUnread(index + 1); // show only if previous message is read
|
|
621
|
-
|
|
622
|
-
if (message.type === 'system') {
|
|
623
|
-
return (
|
|
624
|
-
<View style={[shouldApplyAndroidWorkaround ? styles.invertAndroid : undefined]}>
|
|
625
|
-
<View testID={`message-list-item-${index}`}>
|
|
626
|
-
<MessageSystem
|
|
627
|
-
message={message}
|
|
628
|
-
style={[{ paddingHorizontal: screenPadding }, messageContainer]}
|
|
629
|
-
/>
|
|
630
|
-
</View>
|
|
631
|
-
{insertInlineUnreadIndicator && <InlineUnreadIndicator />}
|
|
632
|
-
</View>
|
|
633
|
-
);
|
|
634
|
-
}
|
|
672
|
+
const showUnreadUnderlay = !!shouldShowUnreadUnderlay && showUnreadSeparator;
|
|
635
673
|
|
|
636
674
|
const wrapMessageInTheme = client.userID === message.user?.id && !!myMessageTheme;
|
|
637
675
|
const renderDateSeperator = isMessageWithStylesReadByAndDateSeparator(message) &&
|
|
@@ -640,7 +678,7 @@ const MessageListWithContext = <
|
|
|
640
678
|
<Message
|
|
641
679
|
goToMessage={goToMessage}
|
|
642
680
|
groupStyles={isMessageWithStylesReadByAndDateSeparator(message) ? message.groupStyles : []}
|
|
643
|
-
isTargetedMessage={
|
|
681
|
+
isTargetedMessage={highlightedMessageId === message.id}
|
|
644
682
|
lastReceivedId={
|
|
645
683
|
lastReceivedId === message.id || message.quoted_message_id ? lastReceivedId : undefined
|
|
646
684
|
}
|
|
@@ -651,33 +689,32 @@ const MessageListWithContext = <
|
|
|
651
689
|
threadList={threadList}
|
|
652
690
|
/>
|
|
653
691
|
);
|
|
692
|
+
|
|
654
693
|
return (
|
|
655
|
-
|
|
656
|
-
{
|
|
694
|
+
<View
|
|
695
|
+
style={[shouldApplyAndroidWorkaround ? styles.invertAndroid : undefined]}
|
|
696
|
+
testID={`message-list-item-${index}`}
|
|
697
|
+
>
|
|
698
|
+
{message.type === 'system' ? (
|
|
699
|
+
<MessageSystem
|
|
700
|
+
message={message}
|
|
701
|
+
style={[{ paddingHorizontal: screenPadding }, messageContainer]}
|
|
702
|
+
/>
|
|
703
|
+
) : wrapMessageInTheme ? (
|
|
657
704
|
<ThemeProvider mergedStyle={modifiedTheme}>
|
|
658
|
-
<View
|
|
659
|
-
|
|
660
|
-
testID={`message-list-item-${index}`}
|
|
661
|
-
>
|
|
662
|
-
{shouldApplyAndroidWorkaround && renderDateSeperator}
|
|
705
|
+
<View testID={`message-list-item-${index}`}>
|
|
706
|
+
{renderDateSeperator}
|
|
663
707
|
{renderMessage}
|
|
664
708
|
</View>
|
|
665
709
|
</ThemeProvider>
|
|
666
710
|
) : (
|
|
667
|
-
<View
|
|
668
|
-
|
|
669
|
-
testID={`message-list-item-${index}`}
|
|
670
|
-
>
|
|
671
|
-
{shouldApplyAndroidWorkaround && renderDateSeperator}
|
|
711
|
+
<View testID={`message-list-item-${index}`}>
|
|
712
|
+
{renderDateSeperator}
|
|
672
713
|
{renderMessage}
|
|
673
714
|
</View>
|
|
674
715
|
)}
|
|
675
|
-
{
|
|
676
|
-
|
|
677
|
-
<View style={[shouldApplyAndroidWorkaround ? styles.invertAndroid : undefined]}>
|
|
678
|
-
{insertInlineUnreadIndicator && <InlineUnreadIndicator />}
|
|
679
|
-
</View>
|
|
680
|
-
</>
|
|
716
|
+
{showUnreadUnderlay && <InlineUnreadIndicator />}
|
|
717
|
+
</View>
|
|
681
718
|
);
|
|
682
719
|
};
|
|
683
720
|
|
|
@@ -803,8 +840,8 @@ const MessageListWithContext = <
|
|
|
803
840
|
};
|
|
804
841
|
|
|
805
842
|
const handleScroll: ScrollViewProps['onScroll'] = (event) => {
|
|
806
|
-
const offset = event.nativeEvent.contentOffset.y;
|
|
807
843
|
const messageListHasMessages = processedMessageList.length > 0;
|
|
844
|
+
const offset = event.nativeEvent.contentOffset.y;
|
|
808
845
|
// Show scrollToBottom button once scroll position goes beyond 150.
|
|
809
846
|
const isScrollAtBottom = offset <= 150;
|
|
810
847
|
|
|
@@ -821,14 +858,6 @@ const MessageListWithContext = <
|
|
|
821
858
|
*/
|
|
822
859
|
setScrollToBottomButtonVisible(showScrollToBottomButton);
|
|
823
860
|
|
|
824
|
-
const shouldMarkRead = !threadList && !notLatestSet && offset <= 0 && channel.countUnread() > 0;
|
|
825
|
-
|
|
826
|
-
if (shouldMarkRead) {
|
|
827
|
-
markRead();
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
setInitialScrollDone(false);
|
|
831
|
-
|
|
832
861
|
if (onListScroll) {
|
|
833
862
|
onListScroll(event);
|
|
834
863
|
}
|
|
@@ -842,14 +871,12 @@ const MessageListWithContext = <
|
|
|
842
871
|
await reloadChannel();
|
|
843
872
|
} else if (flatListRef.current) {
|
|
844
873
|
flatListRef.current.scrollToOffset({
|
|
874
|
+
animated: true,
|
|
845
875
|
offset: 0,
|
|
846
876
|
});
|
|
847
877
|
}
|
|
848
878
|
|
|
849
879
|
setScrollToBottomButtonVisible(false);
|
|
850
|
-
if (!threadList) {
|
|
851
|
-
markRead();
|
|
852
|
-
}
|
|
853
880
|
};
|
|
854
881
|
|
|
855
882
|
const scrollToIndexFailedRetryCountRef = useRef<number>(0);
|
|
@@ -860,16 +887,12 @@ const MessageListWithContext = <
|
|
|
860
887
|
// We got a failure as we tried to scroll to an item that was outside the render length
|
|
861
888
|
if (!flatListRef.current) return;
|
|
862
889
|
// we don't know the actual size of all items but we can see the average, so scroll to the closest offset
|
|
863
|
-
flatListRef.current.scrollToOffset({
|
|
864
|
-
animated: false,
|
|
865
|
-
offset: info.averageItemLength * info.index,
|
|
866
|
-
});
|
|
867
890
|
// since we used only an average offset... we won't go to the center of the item yet
|
|
868
891
|
// with a little delay to wait for scroll to offset to complete, we can then scroll to the index
|
|
869
892
|
failScrollTimeoutId.current = setTimeout(() => {
|
|
870
893
|
try {
|
|
871
894
|
flatListRef.current?.scrollToIndex({
|
|
872
|
-
animated:
|
|
895
|
+
animated: true,
|
|
873
896
|
index: info.index,
|
|
874
897
|
viewPosition: 0.5, // try to place message in the center of the screen
|
|
875
898
|
});
|
|
@@ -894,81 +917,12 @@ const MessageListWithContext = <
|
|
|
894
917
|
scrollToIndexFailedRetryCountRef.current += 1;
|
|
895
918
|
onScrollToIndexFailedRef.current(info);
|
|
896
919
|
}
|
|
897
|
-
},
|
|
920
|
+
}, WAIT_FOR_SCROLL_TIMEOUT);
|
|
898
921
|
|
|
899
922
|
// Only when index is greater than 0 and in range of items in FlatList
|
|
900
923
|
// this onScrollToIndexFailed will be called again
|
|
901
924
|
});
|
|
902
925
|
|
|
903
|
-
const goToMessage = async (messageId: string) => {
|
|
904
|
-
const indexOfParentInMessageList = processedMessageList.findIndex(
|
|
905
|
-
(message) => message?.id === messageId,
|
|
906
|
-
);
|
|
907
|
-
if (indexOfParentInMessageList !== -1 && flatListRef.current) {
|
|
908
|
-
clearTimeout(failScrollTimeoutId.current);
|
|
909
|
-
scrollToIndexFailedRetryCountRef.current = 0;
|
|
910
|
-
// keep track of this messageId, so that we dont scroll to again in useEffect for targeted message change
|
|
911
|
-
messageIdLastScrolledToRef.current = messageId;
|
|
912
|
-
setTargetedMessage(messageId);
|
|
913
|
-
// now scroll to it with animated=true (in useEffect animated=false is used)
|
|
914
|
-
flatListRef.current.scrollToIndex({
|
|
915
|
-
animated: true,
|
|
916
|
-
index: indexOfParentInMessageList,
|
|
917
|
-
viewPosition: 0.5, // try to place message in the center of the screen
|
|
918
|
-
});
|
|
919
|
-
return;
|
|
920
|
-
}
|
|
921
|
-
// the message we want was not loaded yet, so lets load it
|
|
922
|
-
await loadChannelAroundMessage({ messageId });
|
|
923
|
-
};
|
|
924
|
-
|
|
925
|
-
/**
|
|
926
|
-
* Check if a messageId needs to be scrolled to after list loads, and scroll to it
|
|
927
|
-
* Note: This effect fires on every list change with a small debounce so that scrolling isnt abrupted by an immediate rerender
|
|
928
|
-
*/
|
|
929
|
-
useEffect(() => {
|
|
930
|
-
scrollToDebounceTimeoutRef.current = setTimeout(() => {
|
|
931
|
-
if (initialScrollToFirstUnreadMessage) {
|
|
932
|
-
clearTimeout(initialScrollSettingTimeoutRef.current);
|
|
933
|
-
initialScrollSettingTimeoutRef.current = setTimeout(() => {
|
|
934
|
-
// small timeout to ensure that handleScroll is called after scrollToIndex to set this flag
|
|
935
|
-
setInitialScrollDone(true);
|
|
936
|
-
}, 2000);
|
|
937
|
-
}
|
|
938
|
-
let messageIdToScroll: string | undefined;
|
|
939
|
-
if (targetedMessage && messageIdLastScrolledToRef.current !== targetedMessage) {
|
|
940
|
-
// if some messageId was targeted but not scrolledTo yet
|
|
941
|
-
// we have scroll to there after loading completes
|
|
942
|
-
messageIdToScroll = targetedMessage;
|
|
943
|
-
}
|
|
944
|
-
if (!messageIdToScroll) return;
|
|
945
|
-
const indexOfParentInMessageList = processedMessageList.findIndex(
|
|
946
|
-
(message) => message?.id === messageIdToScroll,
|
|
947
|
-
);
|
|
948
|
-
if (indexOfParentInMessageList !== -1 && flatListRef.current) {
|
|
949
|
-
// By a fresh scroll we should clear the retries for the previous failed scroll
|
|
950
|
-
clearTimeout(scrollToDebounceTimeoutRef.current);
|
|
951
|
-
clearTimeout(failScrollTimeoutId.current);
|
|
952
|
-
// keep track of this messageId, so that we dont scroll to again for targeted message change
|
|
953
|
-
messageIdLastScrolledToRef.current = messageIdToScroll;
|
|
954
|
-
// reset the retry count
|
|
955
|
-
scrollToIndexFailedRetryCountRef.current = 0;
|
|
956
|
-
// now scroll to it
|
|
957
|
-
flatListRef.current.scrollToIndex({
|
|
958
|
-
animated: false,
|
|
959
|
-
index: indexOfParentInMessageList,
|
|
960
|
-
viewPosition: 0.5, // try to place message in the center of the screen
|
|
961
|
-
});
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
// the message we want to scroll to has not been loaded in the state yet
|
|
965
|
-
if (indexOfParentInMessageList === -1) {
|
|
966
|
-
loadChannelAroundMessage({ messageId: messageIdToScroll });
|
|
967
|
-
}
|
|
968
|
-
}, 50);
|
|
969
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
970
|
-
}, [targetedMessage, initialScrollToFirstUnreadMessage]);
|
|
971
|
-
|
|
972
926
|
const messagesWithImages =
|
|
973
927
|
legacyImageViewerSwipeBehaviour &&
|
|
974
928
|
processedMessageList.filter((message) => {
|
|
@@ -1047,6 +1001,11 @@ const MessageListWithContext = <
|
|
|
1047
1001
|
}
|
|
1048
1002
|
};
|
|
1049
1003
|
|
|
1004
|
+
const onUnreadNotificationClose = async () => {
|
|
1005
|
+
await markRead();
|
|
1006
|
+
setIsUnreadNotificationOpen(false);
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1050
1009
|
const debugRef = useDebugContext();
|
|
1051
1010
|
|
|
1052
1011
|
const isDebugModeEnabled = __DEV__ && debugRef && debugRef.current;
|
|
@@ -1155,7 +1114,7 @@ const MessageListWithContext = <
|
|
|
1155
1114
|
onScrollEndDrag={onScrollEndDrag}
|
|
1156
1115
|
onScrollToIndexFailed={onScrollToIndexFailedRef.current}
|
|
1157
1116
|
onTouchEnd={dismissImagePicker}
|
|
1158
|
-
onViewableItemsChanged={onViewableItemsChanged
|
|
1117
|
+
onViewableItemsChanged={onViewableItemsChanged}
|
|
1159
1118
|
ref={refCallback}
|
|
1160
1119
|
renderItem={renderItem}
|
|
1161
1120
|
scrollEnabled={overlay === 'none'}
|
|
@@ -1187,6 +1146,9 @@ const MessageListWithContext = <
|
|
|
1187
1146
|
unreadCount={threadList ? 0 : channel?.countUnread()}
|
|
1188
1147
|
/>
|
|
1189
1148
|
<NetworkDownIndicator />
|
|
1149
|
+
{isUnreadNotificationOpen && !threadList ? (
|
|
1150
|
+
<UnreadMessagesNotification onCloseHandler={onUnreadNotificationClose} />
|
|
1151
|
+
) : null}
|
|
1190
1152
|
</View>
|
|
1191
1153
|
);
|
|
1192
1154
|
};
|
|
@@ -1203,11 +1165,13 @@ export const MessageList = <
|
|
|
1203
1165
|
const { closePicker, selectedPicker, setSelectedPicker } = useAttachmentPickerContext();
|
|
1204
1166
|
const {
|
|
1205
1167
|
channel,
|
|
1168
|
+
channelUnreadState,
|
|
1206
1169
|
disabled,
|
|
1207
1170
|
EmptyStateIndicator,
|
|
1208
1171
|
enableMessageGroupingByUser,
|
|
1209
1172
|
error,
|
|
1210
1173
|
hideStickyDateHeader,
|
|
1174
|
+
highlightedMessageId,
|
|
1211
1175
|
isChannelActive,
|
|
1212
1176
|
loadChannelAroundMessage,
|
|
1213
1177
|
loading,
|
|
@@ -1227,7 +1191,6 @@ export const MessageList = <
|
|
|
1227
1191
|
DateHeader,
|
|
1228
1192
|
disableTypingIndicator,
|
|
1229
1193
|
FlatList,
|
|
1230
|
-
initialScrollToFirstUnreadMessage,
|
|
1231
1194
|
InlineDateSeparator,
|
|
1232
1195
|
InlineUnreadIndicator,
|
|
1233
1196
|
legacyImageViewerSwipeBehaviour,
|
|
@@ -1238,6 +1201,7 @@ export const MessageList = <
|
|
|
1238
1201
|
shouldShowUnreadUnderlay,
|
|
1239
1202
|
TypingIndicator,
|
|
1240
1203
|
TypingIndicatorContainer,
|
|
1204
|
+
UnreadMessagesNotification,
|
|
1241
1205
|
} = useMessagesContext<StreamChatGenerics>();
|
|
1242
1206
|
const { loadMore, loadMoreRecent } = usePaginatedMessageListContext<StreamChatGenerics>();
|
|
1243
1207
|
const { overlay } = useOverlayContext();
|
|
@@ -1248,6 +1212,7 @@ export const MessageList = <
|
|
|
1248
1212
|
<MessageListWithContext
|
|
1249
1213
|
{...{
|
|
1250
1214
|
channel,
|
|
1215
|
+
channelUnreadState,
|
|
1251
1216
|
client,
|
|
1252
1217
|
closePicker,
|
|
1253
1218
|
DateHeader,
|
|
@@ -1258,7 +1223,7 @@ export const MessageList = <
|
|
|
1258
1223
|
error,
|
|
1259
1224
|
FlatList,
|
|
1260
1225
|
hideStickyDateHeader,
|
|
1261
|
-
|
|
1226
|
+
highlightedMessageId,
|
|
1262
1227
|
InlineDateSeparator,
|
|
1263
1228
|
InlineUnreadIndicator,
|
|
1264
1229
|
isListActive: isChannelActive,
|
|
@@ -1291,6 +1256,7 @@ export const MessageList = <
|
|
|
1291
1256
|
threadList,
|
|
1292
1257
|
TypingIndicator,
|
|
1293
1258
|
TypingIndicatorContainer,
|
|
1259
|
+
UnreadMessagesNotification,
|
|
1294
1260
|
}}
|
|
1295
1261
|
{...props}
|
|
1296
1262
|
noGroupByUser={!enableMessageGroupingByUser || props.noGroupByUser}
|