@droppii-org/chat-mobile 0.2.109 → 0.2.110

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 (100) hide show
  1. package/lib/module/screens/chat-detail/ChatDetail.js +42 -7
  2. package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
  3. package/lib/module/screens/chat-detail/ChatListLegend.js +249 -49
  4. package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
  5. package/lib/module/screens/chat-detail/hooks/createUnreadMarkReadGate.js +32 -0
  6. package/lib/module/screens/chat-detail/hooks/createUnreadMarkReadGate.js.map +1 -0
  7. package/lib/module/screens/chat-detail/hooks/useMarkConversationRead.js +180 -0
  8. package/lib/module/screens/chat-detail/hooks/useMarkConversationRead.js.map +1 -0
  9. package/lib/module/screens/chat-detail/hooks/useUnreadAnchorSeen.js +88 -0
  10. package/lib/module/screens/chat-detail/hooks/useUnreadAnchorSeen.js.map +1 -0
  11. package/lib/module/screens/chat-detail/hooks/useUnreadDeeplinkCheck.js +59 -0
  12. package/lib/module/screens/chat-detail/hooks/useUnreadDeeplinkCheck.js.map +1 -0
  13. package/lib/module/screens/chat-detail/hooks/useUnreadIndicator.js +105 -0
  14. package/lib/module/screens/chat-detail/hooks/useUnreadIndicator.js.map +1 -0
  15. package/lib/module/screens/chat-detail/hooks/useUnreadIndicatorInList.js +157 -0
  16. package/lib/module/screens/chat-detail/hooks/useUnreadIndicatorInList.js.map +1 -0
  17. package/lib/module/screens/chat-detail/legend/LegendChatUnreadButton.js +140 -0
  18. package/lib/module/screens/chat-detail/legend/LegendChatUnreadButton.js.map +1 -0
  19. package/lib/module/screens/chat-detail/legend/LegendChatUnreadDivider.js +51 -0
  20. package/lib/module/screens/chat-detail/legend/LegendChatUnreadDivider.js.map +1 -0
  21. package/lib/module/services/message.js +30 -0
  22. package/lib/module/services/message.js.map +1 -1
  23. package/lib/module/store/message.js +25 -4
  24. package/lib/module/store/message.js.map +1 -1
  25. package/lib/module/store/unreadIndicator.js +26 -0
  26. package/lib/module/store/unreadIndicator.js.map +1 -0
  27. package/lib/module/translation/resources/i18n.js +2 -0
  28. package/lib/module/translation/resources/i18n.js.map +1 -1
  29. package/lib/module/types/chat.js.map +1 -1
  30. package/lib/module/types/unreadIndicator.js +2 -0
  31. package/lib/module/types/unreadIndicator.js.map +1 -0
  32. package/lib/module/utils/markReadPolicy.js +25 -0
  33. package/lib/module/utils/markReadPolicy.js.map +1 -0
  34. package/lib/module/utils/promise.js +16 -0
  35. package/lib/module/utils/promise.js.map +1 -1
  36. package/lib/module/utils/unreadAnchor.js +57 -0
  37. package/lib/module/utils/unreadAnchor.js.map +1 -0
  38. package/lib/module/utils/unreadIndicatorState.js +96 -0
  39. package/lib/module/utils/unreadIndicatorState.js.map +1 -0
  40. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
  41. package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts +4 -1
  42. package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts.map +1 -1
  43. package/lib/typescript/src/screens/chat-detail/hooks/createUnreadMarkReadGate.d.ts +9 -0
  44. package/lib/typescript/src/screens/chat-detail/hooks/createUnreadMarkReadGate.d.ts.map +1 -0
  45. package/lib/typescript/src/screens/chat-detail/hooks/useMarkConversationRead.d.ts +39 -0
  46. package/lib/typescript/src/screens/chat-detail/hooks/useMarkConversationRead.d.ts.map +1 -0
  47. package/lib/typescript/src/screens/chat-detail/hooks/useUnreadAnchorSeen.d.ts +26 -0
  48. package/lib/typescript/src/screens/chat-detail/hooks/useUnreadAnchorSeen.d.ts.map +1 -0
  49. package/lib/typescript/src/screens/chat-detail/hooks/useUnreadDeeplinkCheck.d.ts +17 -0
  50. package/lib/typescript/src/screens/chat-detail/hooks/useUnreadDeeplinkCheck.d.ts.map +1 -0
  51. package/lib/typescript/src/screens/chat-detail/hooks/useUnreadIndicator.d.ts +21 -0
  52. package/lib/typescript/src/screens/chat-detail/hooks/useUnreadIndicator.d.ts.map +1 -0
  53. package/lib/typescript/src/screens/chat-detail/hooks/useUnreadIndicatorInList.d.ts +35 -0
  54. package/lib/typescript/src/screens/chat-detail/hooks/useUnreadIndicatorInList.d.ts.map +1 -0
  55. package/lib/typescript/src/screens/chat-detail/legend/LegendChatUnreadButton.d.ts +8 -0
  56. package/lib/typescript/src/screens/chat-detail/legend/LegendChatUnreadButton.d.ts.map +1 -0
  57. package/lib/typescript/src/screens/chat-detail/legend/LegendChatUnreadDivider.d.ts +7 -0
  58. package/lib/typescript/src/screens/chat-detail/legend/LegendChatUnreadDivider.d.ts.map +1 -0
  59. package/lib/typescript/src/services/message.d.ts +8 -0
  60. package/lib/typescript/src/services/message.d.ts.map +1 -1
  61. package/lib/typescript/src/store/message.d.ts.map +1 -1
  62. package/lib/typescript/src/store/unreadIndicator.d.ts +10 -0
  63. package/lib/typescript/src/store/unreadIndicator.d.ts.map +1 -0
  64. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  65. package/lib/typescript/src/types/chat.d.ts +3 -0
  66. package/lib/typescript/src/types/chat.d.ts.map +1 -1
  67. package/lib/typescript/src/types/events.d.ts +17 -1
  68. package/lib/typescript/src/types/events.d.ts.map +1 -1
  69. package/lib/typescript/src/types/unreadIndicator.d.ts +45 -0
  70. package/lib/typescript/src/types/unreadIndicator.d.ts.map +1 -0
  71. package/lib/typescript/src/utils/markReadPolicy.d.ts +27 -0
  72. package/lib/typescript/src/utils/markReadPolicy.d.ts.map +1 -0
  73. package/lib/typescript/src/utils/promise.d.ts +6 -0
  74. package/lib/typescript/src/utils/promise.d.ts.map +1 -1
  75. package/lib/typescript/src/utils/unreadAnchor.d.ts +33 -0
  76. package/lib/typescript/src/utils/unreadAnchor.d.ts.map +1 -0
  77. package/lib/typescript/src/utils/unreadIndicatorState.d.ts +26 -0
  78. package/lib/typescript/src/utils/unreadIndicatorState.d.ts.map +1 -0
  79. package/package.json +2 -2
  80. package/src/screens/chat-detail/ChatDetail.tsx +58 -5
  81. package/src/screens/chat-detail/ChatListLegend.tsx +314 -46
  82. package/src/screens/chat-detail/hooks/createUnreadMarkReadGate.ts +41 -0
  83. package/src/screens/chat-detail/hooks/useMarkConversationRead.ts +197 -0
  84. package/src/screens/chat-detail/hooks/useUnreadAnchorSeen.ts +105 -0
  85. package/src/screens/chat-detail/hooks/useUnreadDeeplinkCheck.ts +68 -0
  86. package/src/screens/chat-detail/hooks/useUnreadIndicator.ts +112 -0
  87. package/src/screens/chat-detail/hooks/useUnreadIndicatorInList.ts +181 -0
  88. package/src/screens/chat-detail/legend/LegendChatUnreadButton.tsx +165 -0
  89. package/src/screens/chat-detail/legend/LegendChatUnreadDivider.tsx +52 -0
  90. package/src/services/message.ts +42 -0
  91. package/src/store/message.ts +23 -5
  92. package/src/store/unreadIndicator.ts +38 -0
  93. package/src/translation/resources/i18n.ts +2 -0
  94. package/src/types/chat.ts +3 -0
  95. package/src/types/events.ts +18 -1
  96. package/src/types/unreadIndicator.ts +49 -0
  97. package/src/utils/markReadPolicy.ts +55 -0
  98. package/src/utils/promise.ts +20 -0
  99. package/src/utils/unreadAnchor.ts +87 -0
  100. package/src/utils/unreadIndicatorState.ts +131 -0
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- import { memo, useCallback, useEffect, useRef } from 'react';
3
+ import { memo, useCallback, useEffect, useMemo, useRef } from 'react';
4
4
  import { DeviceEventEmitter } from 'react-native';
5
5
  import { useKeyboardScrollToEnd } from '@legendapp/list/keyboard';
6
6
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -22,7 +22,7 @@ import { shouldShowAddMember } from "./conversationHeader.utils.js";
22
22
  import { normalizeUrl } from "../../utils/url.js";
23
23
  import { MessageToolboxOverlay } from "./messageToolbox/MessageToolboxOverlay.js";
24
24
  import { useGetConversationDetail, useGetConversationTarget, useSyncConversationById } from "../../hooks/conversation/useGetConversationDetail.js";
25
- import { GroupJoinSource } from '@droppii/openim-rn-client-sdk';
25
+ import { GroupJoinSource, PeerType } from '@droppii/openim-rn-client-sdk';
26
26
  import { useMessages } from "../../hooks/message/useMessages.js";
27
27
  import { ChatEvent } from "../../types/events.js";
28
28
  import { useSetIsShowFLashMessage } from "../../context/global.js";
@@ -32,7 +32,8 @@ import { useSingleAccessGuard } from "../../hooks/conversation/useSingleAccessGu
32
32
  import { useIsJoinedGroup } from "../../hooks/useIsJoinedGroup.js";
33
33
  import { UIUtils } from "../../utils/UIUtils.js";
34
34
  import { trans } from "../../translation/index.js";
35
- import { getGroupIdFromConversationId } from "../../utils/conversation.js";
35
+ import { getGroupIdFromConversationId, isConversationParticipant, isSingleConversationId } from "../../utils/conversation.js";
36
+ import { useUnreadIndicator } from "./hooks/useUnreadIndicator.js";
36
37
  import { ChatDetailLoading } from "./components/ChatDetailLoading.js";
37
38
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
38
39
  const ChatDetail = /*#__PURE__*/memo(({
@@ -75,6 +76,25 @@ const ChatDetail = /*#__PURE__*/memo(({
75
76
  const handleMediaPress = useCallback((items, index) => {
76
77
  mediaViewerRef.current?.show(items, index);
77
78
  }, []);
79
+
80
+ // Bot from the conversation itself: ChatDetailContext's flag is derived
81
+ // from an id this screen sets in an effect, so it's still false on the
82
+ // first effect pass.
83
+ const isBotThread = conversation?.peerType === PeerType.Bot;
84
+ // 1v1: only a participant may look up / mark read. Groups: the gate's
85
+ // `isReady` already enforced join/access before this screen mounted.
86
+ const accessConfirmed = !!currentUser?.userID && (!isSingleConversationId(conversationId) || isConversationParticipant(conversationId, currentUser.userID));
87
+ // Must stay above useMessages (see useUnreadDeeplinkCheck).
88
+ const {
89
+ unreadToken,
90
+ unreadTokenRef,
91
+ markChildNavigation
92
+ } = useUnreadIndicator({
93
+ conversationId,
94
+ isBotConversation: isBotThread,
95
+ targetMessageId,
96
+ accessConfirmed
97
+ });
78
98
  const {
79
99
  messages,
80
100
  initLoading,
@@ -166,9 +186,21 @@ const ChatDetail = /*#__PURE__*/memo(({
166
186
  }
167
187
  });
168
188
  }, [currentUser, unpinMessage, customMessageItemFactory]);
189
+
190
+ // Library-initiated child navigation keeps the unread indicator across the
191
+ // blur it causes; markChildNavigation must run before the callback does.
169
192
  const handlePressMenu = useCallback(() => {
193
+ markChildNavigation();
170
194
  onPressMenu?.(conversationId);
171
- }, [conversationId, onPressMenu]);
195
+ }, [conversationId, onPressMenu, markChildNavigation]);
196
+ const handlePressSearch = useMemo(() => onPressSearch ? id => {
197
+ markChildNavigation();
198
+ onPressSearch(id);
199
+ } : undefined, [onPressSearch, markChildNavigation]);
200
+ const handlePressAddMember = useMemo(() => onPressAddMember ? () => {
201
+ markChildNavigation();
202
+ onPressAddMember();
203
+ } : undefined, [onPressAddMember, markChildNavigation]);
172
204
  const handlePressJoinGroup = useCallback(() => {
173
205
  if (!conversation?.groupID) return;
174
206
  joinGroup({
@@ -186,8 +218,8 @@ const ChatDetail = /*#__PURE__*/memo(({
186
218
  targetUserId: targetUserId,
187
219
  showAddMember: resolvedShowAddMember,
188
220
  onBack: onBack ?? handleBackDefault,
189
- onPressSearch: onPressSearch,
190
- onPressAddMember: onPressAddMember,
221
+ onPressSearch: handlePressSearch,
222
+ onPressAddMember: handlePressAddMember,
191
223
  onPressMenu: handlePressMenu,
192
224
  onPressAvatar: handlePressMenu
193
225
  }), /*#__PURE__*/_jsx(PinnedMessageBar, {
@@ -217,7 +249,10 @@ const ChatDetail = /*#__PURE__*/memo(({
217
249
  renderConversationViewHeader: renderConversationViewHeader,
218
250
  dismissAreaTouchProps: dismissAreaTouchProps,
219
251
  isComposerPanelOpen: isComposerPanelOpen,
220
- onDismissAreaScrollBeginDrag: notifyScrollBeginDrag
252
+ onDismissAreaScrollBeginDrag: notifyScrollBeginDrag,
253
+ unreadToken: unreadToken,
254
+ unreadTokenRef: unreadTokenRef,
255
+ deeplinkTargetId: targetMessageId || undefined
221
256
  })
222
257
  }), /*#__PURE__*/_jsx(ChatComposer, {
223
258
  isEmptyMessage: messages?.length === 0,
@@ -1 +1 @@
1
- {"version":3,"names":["memo","useCallback","useEffect","useRef","DeviceEventEmitter","useKeyboardScrollToEnd","useSafeAreaInsets","KContainer","useNavigation","useRoute","usePinMessage","PinnedMessageBar","openPinnedMessagesSheet","MediaViewerModal","useConversation","useConversationStore","useUserStore","useExpandedMessageStore","clearExpandableTextCache","ChatDetailHeader","ChatListLegend","ChatComposer","useComposerPanelDismiss","TimelinePressGuardProvider","shouldShowAddMember","normalizeUrl","MessageToolboxOverlay","useGetConversationDetail","useGetConversationTarget","useSyncConversationById","GroupJoinSource","useMessages","ChatEvent","useSetIsShowFLashMessage","useJoinGroup","useGroupAccessGuard","useSingleAccessGuard","useIsJoinedGroup","UIUtils","trans","getGroupIdFromConversationId","ChatDetailLoading","jsx","_jsx","jsxs","_jsxs","ChatDetail","conversationId","targetUserId","targetGroupId","targetMessageId","showAddMember","onBack","onPressSearch","onPressAddMember","onPressMenu","onPressUrl","customMessageItemFactory","pannelActions","groupJoinSource","renderConversationViewHeader","navigation","mediaViewerRef","messageToolboxRef","currentUser","s","user","conversation","getState","clearSurface","data","target","isComposeDisabled","isActive","handleBackDefault","goBack","handleMediaPress","items","index","current","show","messages","initLoading","moreOldLoading","moreNewLoading","getMoreOldMessages","getMoreNewMessages","hasMoreOld","hasMoreNew","startClientMsgId","peerType","mutate","joinGroup","isPending","isJoiningGroup","setShowFLashMessage","pinnedMessages","pinMessage","unpinMessage","setCurrentConversation","undefined","subscription","addListener","TargetMessageUnavailable","toast","open","title","theme","remove","params","targetMessage","find","m","clientMsgID","emit","ScrollToMessage","clientMessageId","resolvedShowAddMember","insets","listRef","freeze","scrollMessageToEnd","handlePressUrl","url","panelControllerRef","isComposerPanelOpen","onComposerPanelOpenChange","dismissAreaTouchProps","notifyScrollBeginDrag","shouldSwallowPress","handleMessageLongPress","message","rect","groupPosition","handlePressPinnedMessageBar","currentUserId","userID","onPressMessage","handlePressMenu","handlePressJoinGroup","groupID","reqMsg","joinSource","Search","groupName","showName","Page","flex","edges","children","onPressAvatar","onPress","value","isLoading","onLoadMoreOld","onLoadMoreNew","onMediaPress","onLongPress","keyboardOffset","bottom","onDismissAreaScrollBeginDrag","isEmptyMessage","length","onPressJoinGroup","onPanelOpenChange","ref","onPinMessage","onUnpinMessage","ConversationDataGate","props","targetConversationId","targetBotId","hasTarget","isLoadingConversation","isFetching","isSyncingConversation","isFetched","isConversationSynced","isCheckingJoinStatus","handleAccessBlocked","isCheckingAccess","isBlockedAccess","onBlocked","isConversationResolved","isReady","SdkReadyGate","isUserLoaded"],"sourceRoot":"../../../../src","sources":["screens/chat-detail/ChatDetail.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["memo","useCallback","useEffect","useMemo","useRef","DeviceEventEmitter","useKeyboardScrollToEnd","useSafeAreaInsets","KContainer","useNavigation","useRoute","usePinMessage","PinnedMessageBar","openPinnedMessagesSheet","MediaViewerModal","useConversation","useConversationStore","useUserStore","useExpandedMessageStore","clearExpandableTextCache","ChatDetailHeader","ChatListLegend","ChatComposer","useComposerPanelDismiss","TimelinePressGuardProvider","shouldShowAddMember","normalizeUrl","MessageToolboxOverlay","useGetConversationDetail","useGetConversationTarget","useSyncConversationById","GroupJoinSource","PeerType","useMessages","ChatEvent","useSetIsShowFLashMessage","useJoinGroup","useGroupAccessGuard","useSingleAccessGuard","useIsJoinedGroup","UIUtils","trans","getGroupIdFromConversationId","isConversationParticipant","isSingleConversationId","useUnreadIndicator","ChatDetailLoading","jsx","_jsx","jsxs","_jsxs","ChatDetail","conversationId","targetUserId","targetGroupId","targetMessageId","showAddMember","onBack","onPressSearch","onPressAddMember","onPressMenu","onPressUrl","customMessageItemFactory","pannelActions","groupJoinSource","renderConversationViewHeader","navigation","mediaViewerRef","messageToolboxRef","currentUser","s","user","conversation","getState","clearSurface","data","target","isComposeDisabled","isActive","handleBackDefault","goBack","handleMediaPress","items","index","current","show","isBotThread","peerType","Bot","accessConfirmed","userID","unreadToken","unreadTokenRef","markChildNavigation","isBotConversation","messages","initLoading","moreOldLoading","moreNewLoading","getMoreOldMessages","getMoreNewMessages","hasMoreOld","hasMoreNew","startClientMsgId","mutate","joinGroup","isPending","isJoiningGroup","setShowFLashMessage","pinnedMessages","pinMessage","unpinMessage","setCurrentConversation","undefined","subscription","addListener","TargetMessageUnavailable","toast","open","title","theme","remove","params","targetMessage","find","m","clientMsgID","emit","ScrollToMessage","clientMessageId","resolvedShowAddMember","insets","listRef","freeze","scrollMessageToEnd","handlePressUrl","url","panelControllerRef","isComposerPanelOpen","onComposerPanelOpenChange","dismissAreaTouchProps","notifyScrollBeginDrag","shouldSwallowPress","handleMessageLongPress","message","rect","groupPosition","handlePressPinnedMessageBar","currentUserId","onPressMessage","handlePressMenu","handlePressSearch","id","handlePressAddMember","handlePressJoinGroup","groupID","reqMsg","joinSource","Search","groupName","showName","Page","flex","edges","children","onPressAvatar","onPress","value","isLoading","onLoadMoreOld","onLoadMoreNew","onMediaPress","onLongPress","keyboardOffset","bottom","onDismissAreaScrollBeginDrag","deeplinkTargetId","isEmptyMessage","length","onPressJoinGroup","onPanelOpenChange","ref","onPinMessage","onUnpinMessage","ConversationDataGate","props","targetConversationId","targetBotId","hasTarget","isLoadingConversation","isFetching","isSyncingConversation","isFetched","isConversationSynced","isCheckingJoinStatus","handleAccessBlocked","isCheckingAccess","isBlockedAccess","onBlocked","isConversationResolved","isReady","SdkReadyGate","isUserLoaded"],"sourceRoot":"../../../../src","sources":["screens/chat-detail/ChatDetail.tsx"],"mappings":"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","ignoreList":[]}
@@ -22,7 +22,6 @@ import { useChatContext } from "../../context/index.js";
22
22
  import { messageStyles } from "./legend/messageTypes.js";
23
23
  import { MessageType, PeerType } from '@droppii/openim-rn-client-sdk';
24
24
  import { useUserStore } from "../../store/index.js";
25
- import { ChatMessageAPI } from "../../services/index.js";
26
25
  import { resolveImageDisplayDims } from "../../components/messages/imageMessage/index.js";
27
26
  import ChatImageDimens, { CHAT_IMAGE_VIEW_SOURCE } from "../../utils/chatImageDimens.js";
28
27
  import { ChatTypingIndicator } from "./ChatTypingIndicator.js";
@@ -30,6 +29,17 @@ import { useGuardedPress } from "../../hooks/useGuardedPress.js";
30
29
  import { useDismissKeyboardFirst } from "../../hooks/useDismissKeyboardFirst.js";
31
30
  import { useTimelinePressGuard } from "../../context/TimelinePressGuardContext.js";
32
31
  import { perfMark } from "../../utils/perf-marker.js";
32
+ import { useMarkConversationRead } from "./hooks/useMarkConversationRead.js";
33
+ import { createUnreadMarkReadGate } from "./hooks/createUnreadMarkReadGate.js";
34
+ import { useUnreadIndicatorInList } from "./hooks/useUnreadIndicatorInList.js";
35
+ import { LegendChatUnreadDivider } from "./legend/LegendChatUnreadDivider.js";
36
+ import { LegendChatUnreadButton } from "./legend/LegendChatUnreadButton.js";
37
+
38
+ // Safety net: a jump that never reports back can't keep the pill logic and
39
+ // the window-reload edge stuck. Long enough for a slow 3-call search plus the
40
+ // unread jump's older-history paging.
41
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
42
+ const JUMP_IN_FLIGHT_TIMEOUT_MS = 20000;
33
43
 
34
44
  // Cluster spacing: a wide gap after the message that closes a cluster, a tight
35
45
  // one between messages inside it. These override the flat margin on the row
@@ -37,7 +47,6 @@ import { perfMark } from "../../utils/perf-marker.js";
37
47
  // which adds only a bottom margin and no vertical padding — so a fixed-size
38
48
  // item's true rendered height stays `content height + this margin`, and
39
49
  // getFixedItemSize can keep folding it in.
40
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
41
50
  const ROW_MARGIN_CLUSTER_END = KSpacingValue['0.5rem'];
42
51
  const ROW_MARGIN_IN_CLUSTER = KSpacingValue['0.25rem'];
43
52
  const BUTTON_FADE_CONFIG = {
@@ -105,7 +114,10 @@ export const ChatListLegend = /*#__PURE__*/memo(({
105
114
  renderConversationViewHeader,
106
115
  dismissAreaTouchProps,
107
116
  isComposerPanelOpen = false,
108
- onDismissAreaScrollBeginDrag
117
+ onDismissAreaScrollBeginDrag,
118
+ unreadToken = null,
119
+ unreadTokenRef,
120
+ deeplinkTargetId
109
121
  }) => {
110
122
  const currentUserId = useUserStore(s => s.user?.userID);
111
123
  const windowWidth = useWindowDimensions().width;
@@ -217,6 +229,68 @@ export const ChatListLegend = /*#__PURE__*/memo(({
217
229
  applicationType
218
230
  } = useChatContext();
219
231
  const searchMessages = useMessageStore(s => s.searchMessages);
232
+
233
+ // True once the list has loaded (onLoad); false while it's remounting
234
+ // under the spinner. Read by the mark-read policy.
235
+ const listLoadedRef = useRef(false);
236
+ // A ScrollToMessage jump is running (in-window scroll or search fallback).
237
+ const jumpInFlightRef = useRef(false);
238
+ // Bumped on every ScrollToMessage, to tell whether a search re-emitted.
239
+ const scrollEventSeqRef = useRef(0);
240
+ const jumpInFlightTimerRef = useRef(null);
241
+ const setJumpInFlight = useCallback(inFlight => {
242
+ jumpInFlightRef.current = inFlight;
243
+ if (jumpInFlightTimerRef.current) {
244
+ clearTimeout(jumpInFlightTimerRef.current);
245
+ jumpInFlightTimerRef.current = null;
246
+ }
247
+ if (!inFlight) return;
248
+ jumpInFlightTimerRef.current = setTimeout(() => {
249
+ jumpInFlightTimerRef.current = null;
250
+ jumpInFlightRef.current = false;
251
+ }, JUMP_IN_FLIGHT_TIMEOUT_MS);
252
+ }, []);
253
+ const markReadGate = useMemo(() => unreadTokenRef ? createUnreadMarkReadGate(unreadTokenRef) : undefined, [unreadTokenRef]);
254
+ const {
255
+ requestMarkRead,
256
+ flushMarkRead
257
+ } = useMarkConversationRead({
258
+ conversationId,
259
+ isAtBottomRef,
260
+ listLoadedRef,
261
+ hasMoreNew: !!hasMoreNew,
262
+ deeplinkTargetId,
263
+ gate: markReadGate
264
+ });
265
+
266
+ // A session that begins already open (bot thread: no lookup) has no
267
+ // resolve transition for the gate to report, so retry a pending
268
+ // mark-read when it lands. Flush-only: landing is not a trigger.
269
+ useEffect(() => {
270
+ if (unreadToken != null) flushMarkRead('gate-open');
271
+ }, [unreadToken, flushMarkRead]);
272
+ const {
273
+ unreadAnchorRowId,
274
+ isPillVisible,
275
+ viewabilityConfig,
276
+ handleViewableItemsChanged,
277
+ checkAnchorSeen,
278
+ markPositionSettled,
279
+ jumpToFirstUnread
280
+ } = useUnreadIndicatorInList({
281
+ messages,
282
+ unreadToken,
283
+ isLoading: !!isLoading,
284
+ hasMoreOld: !!hasMoreOld,
285
+ moreOldLoading: !!moreOldLoading,
286
+ onLoadMoreOld,
287
+ isBotConversation,
288
+ listRef,
289
+ jumpInFlightRef,
290
+ setJumpInFlight
291
+ });
292
+ // With a composer panel open the tap only dismisses it (DROPPII-30577).
293
+ const onPressUnreadPill = useGuardedPress(jumpToFirstUnread, shouldSwallowPress);
220
294
  const handleMessageLongPress = useCallback((messageId, message) => {
221
295
  if (shouldSwallowPress()) return;
222
296
  const node = rowRefsMap.current.get(messageId);
@@ -278,8 +352,12 @@ export const ChatListLegend = /*#__PURE__*/memo(({
278
352
  if ((isLastMessage && conversationFlow?.havingBotMessage === false || isLastIncoming) && isBotConversation) {
279
353
  flowInputButtonsNodes = getFlowInputButtonsNodes(conversationFlow?.flowCurrentStep);
280
354
  }
355
+
356
+ // The first unread row always carries its time label, under the
357
+ // divider.
358
+ const isUnreadAnchor = messageId === unreadAnchorRowId;
281
359
  return /*#__PURE__*/_jsxs(_Fragment, {
282
- children: [(dayStart || timeBreak) && /*#__PURE__*/_jsx(LegendChatDay, {
360
+ children: [isUnreadAnchor && /*#__PURE__*/_jsx(LegendChatUnreadDivider, {}), (isUnreadAnchor || dayStart || timeBreak) && /*#__PURE__*/_jsx(LegendChatDay, {
283
361
  createdAt: createdAt
284
362
  }), /*#__PURE__*/_jsx(KContainer.View, {
285
363
  ref: node => {
@@ -323,7 +401,7 @@ export const ChatListLegend = /*#__PURE__*/memo(({
323
401
  })
324
402
  });
325
403
  }
326
- }, [currentUserId, lastMessageId, messageDataMap, isGroupConversation, isBotConversation, onMediaPress, onPressUrl, onLongPress, handleMessageLongPress, customMessageItemFactory, onResetFlow, onRunFlow, conversationFlow?.flowCurrentStep, conversationFlow?.havingBotMessage, retryMessage, highlightedId, revealedMessageId, handleMessagePress]);
404
+ }, [currentUserId, lastMessageId, messageDataMap, isGroupConversation, isBotConversation, onMediaPress, onPressUrl, onLongPress, handleMessageLongPress, customMessageItemFactory, onResetFlow, onRunFlow, conversationFlow?.flowCurrentStep, conversationFlow?.havingBotMessage, retryMessage, highlightedId, revealedMessageId, handleMessagePress, unreadAnchorRowId]);
327
405
 
328
406
  // `maintainVisibleContentPosition` anchors a prepend to whatever native
329
407
  // view sits at the top. Default `drawDistance` (250px) doesn't survive a
@@ -359,6 +437,9 @@ export const ChatListLegend = /*#__PURE__*/memo(({
359
437
  // Both separators add chrome above the row that this function does not
360
438
  // account for, and a resolved size is never re-measured.
361
439
  if (messageData?.dayStart || messageData?.timeBreak) return undefined;
440
+ // Same for the unread divider. A late anchor changes this function's
441
+ // identity, which makes LegendList re-measure the row.
442
+ if (messageId === unreadAnchorRowId) return undefined;
362
443
 
363
444
  // Incoming rows in a group chat carry an avatar column and a sender
364
445
  // name whose height this function cannot predict — measure them.
@@ -401,7 +482,7 @@ export const ChatListLegend = /*#__PURE__*/memo(({
401
482
  return undefined;
402
483
  }
403
484
  return candidateSize;
404
- }, [messageDataMap, customMessageItemFactory, currentUserId, isGroupConversation, lastMessageId, isBotConversation, conversationFlow?.flowCurrentStep, windowWidth]);
485
+ }, [messageDataMap, customMessageItemFactory, currentUserId, isGroupConversation, lastMessageId, isBotConversation, conversationFlow?.flowCurrentStep, windowWidth, unreadAnchorRowId]);
405
486
 
406
487
  // LegendList only re-renders an item when [itemKey, item, extraData]
407
488
  // changes. Cluster position depends on a message's NEIGHBOURS, which can
@@ -412,8 +493,9 @@ export const ChatListLegend = /*#__PURE__*/memo(({
412
493
  flowStepId: conversationFlow?.flowCurrentStep?.id ?? '',
413
494
  lastMessageId,
414
495
  highlightedId,
415
- revealedMessageId
416
- }), [messageDataMap, conversationFlow?.flowCurrentStep?.id, lastMessageId, highlightedId, revealedMessageId]);
496
+ revealedMessageId,
497
+ unreadAnchorRowId
498
+ }), [messageDataMap, conversationFlow?.flowCurrentStep?.id, lastMessageId, highlightedId, revealedMessageId, unreadAnchorRowId]);
417
499
  const handleStartReached = useCallback(() => {
418
500
  // Both thresholds are checked continuously, including at mount before
419
501
  // any gesture — `hasUserScrolledRef` is what keeps that from firing a
@@ -432,8 +514,10 @@ export const ChatListLegend = /*#__PURE__*/memo(({
432
514
  }, [hasMoreNew, onLoadMoreNew]);
433
515
  const handleScrollBeginDrag = useCallback(() => {
434
516
  hasUserScrolledRef.current = true;
517
+ // The user has taken over: whatever is on screen now is real.
518
+ markPositionSettled();
435
519
  onDismissAreaScrollBeginDrag?.();
436
- }, [onDismissAreaScrollBeginDrag]);
520
+ }, [onDismissAreaScrollBeginDrag, markPositionSettled]);
437
521
  const handleScroll = useCallback(e => {
438
522
  // The keyboard-following loop re-pins to the end on every frame, so
439
523
  // the list is at the bottom for the whole transition by construction.
@@ -461,7 +545,7 @@ export const ChatListLegend = /*#__PURE__*/memo(({
461
545
  // here is smaller than it (55px measured) while still being enough to
462
546
  // leave the newest message behind the composer.
463
547
  const distanceFromEnd = contentSize.height - contentOffset.y - layoutMeasurement.height;
464
- if (grew && distanceFromEnd > 1 && Date.now() < anchorToEndUntilRef.current) {
548
+ if (grew && distanceFromEnd > 1 && !jumpInFlightRef.current && Date.now() < anchorToEndUntilRef.current) {
465
549
  scrollMessageToEnd({
466
550
  animated: true,
467
551
  closeKeyboard: false
@@ -473,15 +557,18 @@ export const ChatListLegend = /*#__PURE__*/memo(({
473
557
  clearTimeout(scrollDebounceRef.current);
474
558
  }
475
559
  scrollDebounceRef.current = setTimeout(() => {
476
- if (isAtBottomRef.current !== isAtBottom) {
560
+ const wasAtBottom = isAtBottomRef.current;
561
+ if (wasAtBottom !== isAtBottom) {
477
562
  isAtBottomRef.current = isAtBottom;
478
563
  buttonOpacity.value = withTiming(isAtBottom ? 0 : 1, BUTTON_FADE_CONFIG);
479
564
  }
480
- if (isAtBottom) {
481
- ChatMessageAPI.markConversationAsRead(conversationId || '');
482
- }
565
+ // Edge-triggered: each call is a server round-trip since rc43.
566
+ if (isAtBottom && !wasAtBottom) requestMarkRead('reached-bottom');
567
+ // Covers slow scrolling while the anchor row stays viewable (no
568
+ // viewability change event). Cheap unless that row is viewable.
569
+ checkAnchorSeen();
483
570
  }, 50);
484
- }, [buttonOpacity, conversationId, scrollMessageToEnd]);
571
+ }, [buttonOpacity, scrollMessageToEnd, requestMarkRead, checkAnchorSeen]);
485
572
  const handleScrollToBottom = useCallback(() => {
486
573
  if (hasMoreNew) {
487
574
  onLoadMoreOld?.(false);
@@ -499,7 +586,8 @@ export const ChatListLegend = /*#__PURE__*/memo(({
499
586
  buttonOpacity.value = withTiming(0, BUTTON_FADE_CONFIG);
500
587
  isAtBottomRef.current = true;
501
588
  setShowBadge(false);
502
- }, [hasMoreNew, onLoadMoreOld, scrollMessageToEnd, buttonOpacity]);
589
+ requestMarkRead('fab');
590
+ }, [hasMoreNew, onLoadMoreOld, scrollMessageToEnd, buttonOpacity, requestMarkRead]);
503
591
 
504
592
  // `paddingBottom` here replaces the one `styles.content` sets via
505
593
  // `paddingVertical`, so the base spacing has to be added back or the last
@@ -691,9 +779,26 @@ export const ChatListLegend = /*#__PURE__*/memo(({
691
779
  // sent or received). Skipped while prepending old history or scrolled
692
780
  // away from the bottom. `moreOldLoading` is read via ref, not a
693
781
  // dependency, so its own start/finish toggle doesn't re-run this.
782
+ const prevLoadingRef = useRef(!!isLoading);
694
783
  useEffect(() => {
784
+ const wasLoading = prevLoadingRef.current;
785
+ prevLoadingRef.current = !!isLoading;
786
+ // Keep the previous id through the spinner.
787
+ if (isLoading) return;
695
788
  const previousLastMessageId = previousLastMessageIdRef.current;
696
789
  previousLastMessageIdRef.current = lastMessageId;
790
+ if (previousLastMessageId === lastMessageId) return;
791
+ // An id change landing with the spinner ending is a window replace
792
+ // (searchMessages / initial fetch), not a new message. Re-aiming at the
793
+ // end here would yank a jump back to the bottom mid-scroll.
794
+ if (wasLoading) return;
795
+
796
+ // Outside `shouldFire`, so it also counts during an old-history prepend.
797
+ // Not for the first id: that's whatever window the list mounted with.
798
+ const last = messagesRef.current[messagesRef.current.length - 1];
799
+ if (previousLastMessageId !== null && last && last.sendID !== currentUserId) {
800
+ requestMarkRead('incoming');
801
+ }
697
802
 
698
803
  // null → a real id is the initial fetch landing (initialScrollAtEnd +
699
804
  // handleListLoad's job), not a new message; a real id → a different
@@ -705,54 +810,144 @@ export const ChatListLegend = /*#__PURE__*/memo(({
705
810
  animated: true,
706
811
  closeKeyboard: false
707
812
  });
708
- }, [lastMessageId, scrollMessageToEnd]);
813
+ }, [lastMessageId, isLoading, scrollMessageToEnd, currentUserId, requestMarkRead]);
814
+
815
+ // A divider appearing late grows the content under a list resting at the
816
+ // end, pushing the last message behind the composer. Re-arm the existing
817
+ // grow → re-aim path in handleScroll; no new scroll call.
818
+ const prevUnreadRowIdRef = useRef(null);
819
+ useEffect(() => {
820
+ const prev = prevUnreadRowIdRef.current;
821
+ prevUnreadRowIdRef.current = unreadAnchorRowId;
822
+ // Only for a list genuinely resting at the true end — never under a
823
+ // jump (a deeplink window lands at its end before scrolling away).
824
+ if (!prev && unreadAnchorRowId && isAtBottomRef.current && !jumpInFlightRef.current && !hasMoreNew && listLoadedRef.current) {
825
+ anchorToEndUntilRef.current = Date.now() + NEW_MESSAGE_ANCHOR_MS;
826
+ }
827
+ }, [unreadAnchorRowId, hasMoreNew]);
828
+
829
+ // The list unmounts under the spinner; `handleListLoad` handles the
830
+ // remount.
831
+ useEffect(() => {
832
+ if (isLoading) listLoadedRef.current = false;
833
+ }, [isLoading]);
709
834
  const handleListLoad = useCallback(() => {
710
- if (hasCorrectedInitialPaddingRef.current) return;
835
+ // Set on every list mount, before the one-shot below.
836
+ listLoadedRef.current = true;
837
+ if (hasCorrectedInitialPaddingRef.current) {
838
+ // A remount after a reload. One that isn't a jump (FAB on a
839
+ // `hasMoreNew` window, a failed search) lands at the end via
840
+ // `initialScrollAtEnd`; a jump owns its own landing.
841
+ requestAnimationFrame(markPositionSettled);
842
+ if (!jumpInFlightRef.current) {
843
+ isAtBottomRef.current = true;
844
+ buttonOpacity.value = withTiming(0, BUTTON_FADE_CONFIG);
845
+ requestMarkRead('window-reload');
846
+ }
847
+ return;
848
+ }
711
849
  hasCorrectedInitialPaddingRef.current = true;
712
850
  perfMark('history_list_loaded');
713
851
  scrollMessageToEnd({
714
852
  animated: false,
715
853
  closeKeyboard: false
716
- });
717
- }, [scrollMessageToEnd]);
854
+ }).finally(() => requestAnimationFrame(markPositionSettled));
855
+ requestMarkRead('list-load');
856
+ }, [scrollMessageToEnd, markPositionSettled, requestMarkRead, buttonOpacity]);
718
857
  useEffect(() => {
719
858
  const bottomSubscription = DeviceEventEmitter.addListener(ChatEvent.ScrollToBottom, handleScrollToBottom);
720
859
  const subscription = DeviceEventEmitter.addListener(ChatEvent.ScrollToMessage, ({
721
- clientMessageId
860
+ clientMessageId,
861
+ highlight = true,
862
+ viewPosition = 0.5,
863
+ viewOffset,
864
+ exitOnUnavailable,
865
+ reemitAfterSearch,
866
+ fromSearch
722
867
  }) => {
723
- const index = messagesRef.current.findIndex(m => m.clientMsgID === clientMessageId);
724
- if (index >= 0) {
725
- try {
726
- listRef.current?.scrollToIndex({
727
- index,
728
- animated: true,
729
- viewPosition: 0.5
730
- }).finally(() => {
731
- if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);
732
- setHighlightedId(clientMessageId);
733
- highlightTimerRef.current = setTimeout(() => setHighlightedId(null), 5000);
734
- });
735
- } catch {
736
- // scrollToIndex throws if item not rendered yet — force refetch messages
737
- searchMessages({
738
- applicationType,
739
- conversationId,
740
- startClientMsgId: clientMessageId
741
- });
868
+ scrollEventSeqRef.current += 1;
869
+ // Not in the window: load one around the target.
870
+ const search = () => {
871
+ // Already the post-search emit: don't search again (loop guard).
872
+ if (fromSearch) {
873
+ setJumpInFlight(false);
874
+ return;
742
875
  }
876
+ // The window replace is not "at bottom": without this the
877
+ // lastMessageId effect and the grow re-aim yank the jump back to
878
+ // the end.
879
+ isAtBottomRef.current = false;
880
+ // Kept in step with the ref: the scroll handler only fades the
881
+ // button on a change, and it would see none from here on.
882
+ buttonOpacity.value = withTiming(1, BUTTON_FADE_CONFIG);
883
+ anchorToEndUntilRef.current = 0;
884
+ setJumpInFlight(true);
885
+ const seq = scrollEventSeqRef.current;
886
+ searchMessages({
887
+ applicationType,
888
+ conversationId,
889
+ startClientMsgId: clientMessageId,
890
+ scrollOptions: {
891
+ highlight,
892
+ viewPosition,
893
+ viewOffset,
894
+ exitOnUnavailable,
895
+ reemitAfterSearch
896
+ }
897
+ }).finally(() => {
898
+ // Finished without re-emitting (search failed): nothing will
899
+ // land, so release the flag now rather than after the timeout.
900
+ // With `reemitAfterSearch: false` the caller owns the landing.
901
+ if (reemitAfterSearch !== false && scrollEventSeqRef.current === seq) {
902
+ setJumpInFlight(false);
903
+ }
904
+ });
905
+ };
906
+
907
+ // Same key as `keyExtractor`, so a server-id-only row is found too.
908
+ const index = messagesRef.current.findIndex(m => (m.clientMsgID || m.serverMsgID) === clientMessageId);
909
+ if (index < 0) {
910
+ search();
743
911
  return;
744
912
  }
745
- searchMessages({
746
- applicationType,
747
- conversationId,
748
- startClientMsgId: clientMessageId
749
- });
913
+ try {
914
+ setJumpInFlight(true);
915
+ // A pending re-aim at the end would pull the jump back down.
916
+ anchorToEndUntilRef.current = 0;
917
+ const scrollToTarget = () => listRef.current?.scrollToIndex({
918
+ index,
919
+ animated: true,
920
+ viewPosition,
921
+ viewOffset
922
+ }) ?? Promise.resolve();
923
+ scrollToTarget()
924
+ // An exact landing (`viewOffset`, the unread jump): the first
925
+ // pass aims with estimated sizes for the rows above, which
926
+ // undershoots by their error (measured ~250dp over ~20 rows)
927
+ // and MVCP then holds that spot. Re-aim once they're measured.
928
+ .then(() => viewOffset == null ? undefined : new Promise(resolve => requestAnimationFrame(() => resolve())).then(scrollToTarget)).finally(() => {
929
+ setJumpInFlight(false);
930
+ markPositionSettled();
931
+ if (!highlight) return;
932
+ if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);
933
+ setHighlightedId(clientMessageId);
934
+ highlightTimerRef.current = setTimeout(() => setHighlightedId(null), 5000);
935
+ });
936
+ } catch {
937
+ // scrollToIndex throws if item not rendered yet — force refetch messages
938
+ search();
939
+ }
750
940
  });
751
941
  return () => {
752
942
  bottomSubscription.remove();
753
943
  subscription.remove();
754
944
  };
755
- }, [applicationType, searchMessages, conversationId, handleScrollToBottom, listRef]);
945
+ }, [applicationType, searchMessages, conversationId, handleScrollToBottom, listRef, setJumpInFlight, markPositionSettled, buttonOpacity]);
946
+ useEffect(() => () => {
947
+ if (jumpInFlightTimerRef.current) {
948
+ clearTimeout(jumpInFlightTimerRef.current);
949
+ }
950
+ }, []);
756
951
  if (isLoading) {
757
952
  return /*#__PURE__*/_jsx(KContainer.View, {
758
953
  flex: true,
@@ -768,10 +963,10 @@ export const ChatListLegend = /*#__PURE__*/memo(({
768
963
  flex: true,
769
964
  background: KColors.white,
770
965
  style: styles.container,
771
- children: [handleRenderConversationViewHeader(), /*#__PURE__*/_jsx(KContainer.View, {
966
+ children: [handleRenderConversationViewHeader(), /*#__PURE__*/_jsxs(KContainer.View, {
772
967
  flex: true,
773
968
  ...dismissAreaTouchProps,
774
- children: /*#__PURE__*/_jsx(KeyboardAwareLegendList, {
969
+ children: [/*#__PURE__*/_jsx(KeyboardAwareLegendList, {
775
970
  ref: listRef,
776
971
  data: messages,
777
972
  renderItem: renderItem
@@ -824,6 +1019,8 @@ export const ChatListLegend = /*#__PURE__*/memo(({
824
1019
  onScroll: handleScroll,
825
1020
  onScrollBeginDrag: handleScrollBeginDrag,
826
1021
  onLoad: handleListLoad,
1022
+ onViewableItemsChanged: handleViewableItemsChanged,
1023
+ viewabilityConfig: viewabilityConfig,
827
1024
  contentContainerStyle: contentContainerStyle,
828
1025
  scrollIndicatorInsets: {
829
1026
  right: 1
@@ -843,7 +1040,10 @@ export const ChatListLegend = /*#__PURE__*/memo(({
843
1040
  onEndReached: handleEndReached,
844
1041
  onEndReachedThreshold: 0.2,
845
1042
  initialScrollAtEnd: true
846
- })
1043
+ }), /*#__PURE__*/_jsx(LegendChatUnreadButton, {
1044
+ visible: isPillVisible,
1045
+ onPress: onPressUnreadPill
1046
+ })]
847
1047
  }), /*#__PURE__*/_jsx(Animated.View, {
848
1048
  style: [styles.scrollToBottomButton, animatedButtonStyle],
849
1049
  children: /*#__PURE__*/_jsxs(KContainer.Touchable, {