@ethora/chat-component-rn 26.7.9 → 26.7.10
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/CHANGELOG.md +3 -0
- package/README.md +10 -0
- package/lib/commonjs/components/MainComponents/ChatRoom.js +63 -15
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +58 -14
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/getServerReadTimestamp.js +66 -3
- package/lib/commonjs/helpers/getServerReadTimestamp.js.map +1 -1
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js +51 -9
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/commonjs/helpers/keyboardLayout.js +12 -2
- package/lib/commonjs/helpers/keyboardLayout.js.map +1 -1
- package/lib/commonjs/helpers/msgSortableMs.js +37 -0
- package/lib/commonjs/helpers/msgSortableMs.js.map +1 -0
- package/lib/commonjs/hooks/useChatRoomFocus.js +31 -7
- package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -1
- package/lib/commonjs/hooks/useLogout.js +8 -0
- package/lib/commonjs/hooks/useLogout.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +66 -32
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/components/MainComponents/ChatRoom.js +65 -17
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/context/xmppProvider.js +59 -15
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/getServerReadTimestamp.js +63 -2
- package/lib/module/helpers/getServerReadTimestamp.js.map +1 -1
- package/lib/module/helpers/insertMessageWithDelimiter.js +52 -9
- package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/module/helpers/keyboardLayout.js +12 -2
- package/lib/module/helpers/keyboardLayout.js.map +1 -1
- package/lib/module/helpers/msgSortableMs.js +32 -0
- package/lib/module/helpers/msgSortableMs.js.map +1 -0
- package/lib/module/hooks/useChatRoomFocus.js +33 -9
- package/lib/module/hooks/useChatRoomFocus.js.map +1 -1
- package/lib/module/hooks/useLogout.js +8 -0
- package/lib/module/hooks/useLogout.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +53 -27
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/getServerReadTimestamp.d.ts +40 -1
- package/lib/typescript/helpers/getServerReadTimestamp.d.ts.map +1 -1
- package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts +1 -1
- package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
- package/lib/typescript/helpers/keyboardLayout.d.ts +5 -1
- package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -1
- package/lib/typescript/helpers/msgSortableMs.d.ts +2 -0
- package/lib/typescript/helpers/msgSortableMs.d.ts.map +1 -0
- package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -1
- package/lib/typescript/hooks/useLogout.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +29 -2
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +1 -0
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/MainComponents/ChatRoom.tsx +68 -17
- package/src/context/xmppProvider.tsx +87 -18
- package/src/helpers/getServerReadTimestamp.ts +79 -2
- package/src/helpers/insertMessageWithDelimiter.ts +55 -19
- package/src/helpers/keyboardLayout.ts +23 -2
- package/src/helpers/msgSortableMs.ts +25 -0
- package/src/hooks/useChatRoomFocus.ts +39 -8
- package/src/hooks/useLogout.tsx +14 -0
- package/src/roomStore/roomsSlice.ts +74 -22
- package/src/types/types.ts +14 -0
|
@@ -4,9 +4,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.FUTURE_READ_MARKER_TOLERANCE_MS = void 0;
|
|
7
|
+
exports.getFlushBoundaryTs = getFlushBoundaryTs;
|
|
8
|
+
exports.getReadMarkerTimestamp = getReadMarkerTimestamp;
|
|
7
9
|
exports.getServerReadTimestamp = getServerReadTimestamp;
|
|
8
10
|
exports.isCorruptFutureReadMarker = isCorruptFutureReadMarker;
|
|
9
|
-
var
|
|
11
|
+
var _msgSortableMs = require("./msgSortableMs");
|
|
10
12
|
// A stored/stamped read marker more than this far past the newest
|
|
11
13
|
// message we actually know about for a room is not "the user is a
|
|
12
14
|
// little ahead" - it's a leftover from a device whose clock was wrong
|
|
@@ -40,7 +42,7 @@ const FUTURE_READ_MARKER_TOLERANCE_MS = exports.FUTURE_READ_MARKER_TOLERANCE_MS
|
|
|
40
42
|
* `heapState.failedMessages` (a send that never reached the server
|
|
41
43
|
* at all).
|
|
42
44
|
*
|
|
43
|
-
* `msgSortableMs` (
|
|
45
|
+
* `msgSortableMs` (helpers/msgSortableMs.ts) reads the server-assigned microsecond
|
|
44
46
|
* timestamp encoded in the first 13 digits of the message id - the same
|
|
45
47
|
* source already used for message ordering and unread counting - so
|
|
46
48
|
* this stays consistent with the rest of the read/unread pipeline.
|
|
@@ -73,7 +75,7 @@ function getServerReadTimestamp(room, heapState) {
|
|
|
73
75
|
if (heapIds.has(id) || failedIds.has(id)) {
|
|
74
76
|
continue;
|
|
75
77
|
}
|
|
76
|
-
const ts = (0,
|
|
78
|
+
const ts = (0, _msgSortableMs.msgSortableMs)(m);
|
|
77
79
|
if (ts > newest) {
|
|
78
80
|
newest = ts;
|
|
79
81
|
}
|
|
@@ -122,4 +124,65 @@ function isCorruptFutureReadMarker(marker, newestAckedMs) {
|
|
|
122
124
|
}
|
|
123
125
|
return marker > Date.now() + FUTURE_READ_MARKER_TOLERANCE_MS;
|
|
124
126
|
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Resolve the marker to STAMP (locally and to the server) for `room`,
|
|
130
|
+
* honouring an explicit read boundary when one is set.
|
|
131
|
+
*
|
|
132
|
+
* Bug #42 (a regression of #33, reintroduced by #38): #38 made every
|
|
133
|
+
* caller stamp the newest server-acknowledged message unconditionally.
|
|
134
|
+
* That is correct for a user who is at the bottom of the room, but wrong
|
|
135
|
+
* for a user who scrolled up, received messages, and left without
|
|
136
|
+
* scrolling back down - stamping "newest" there silently marks
|
|
137
|
+
* messages they never saw as read, both locally and (because the
|
|
138
|
+
* private-store merge is forward-only) permanently on the server.
|
|
139
|
+
*
|
|
140
|
+
* `boundaryTs` is the msgSortableMs of the newest message the user
|
|
141
|
+
* actually reached (see `readBoundaries` on `RoomMessagesState`,
|
|
142
|
+
* populated by MessageList's `onReadBoundaryChange`). When it's set and
|
|
143
|
+
* positive, it wins - but is still clamped to never exceed the newest
|
|
144
|
+
* server-acknowledged message, so a stale/corrupt boundary can't stamp a
|
|
145
|
+
* marker further ahead than the room's own history supports. When no
|
|
146
|
+
* boundary is set (the common case - the user is at the bottom), this is
|
|
147
|
+
* exactly `getServerReadTimestamp`.
|
|
148
|
+
*
|
|
149
|
+
* Never returns `Date.now()`, directly or indirectly - same rule as
|
|
150
|
+
* `getServerReadTimestamp` (bug #38).
|
|
151
|
+
*/
|
|
152
|
+
function getReadMarkerTimestamp(room, heapState, boundaryTs) {
|
|
153
|
+
const newestAcked = getServerReadTimestamp(room, heapState);
|
|
154
|
+
if (typeof boundaryTs === 'number' && Number.isFinite(boundaryTs) && boundaryTs > 0) {
|
|
155
|
+
// `newestAcked === 0` means this room has NOTHING server-acked and no
|
|
156
|
+
// prior marker, so there is nothing to clamp the boundary against -
|
|
157
|
+
// and MessageList derives the boundary from the rendered list, which
|
|
158
|
+
// at that point can only contain pending/failed sends carrying the
|
|
159
|
+
// DEVICE clock via `date`. Returning it here would smuggle a
|
|
160
|
+
// device-clock marker back in through the boundary (bug #38). Return
|
|
161
|
+
// 0 = "nothing to anchor to, skip the write", same contract as
|
|
162
|
+
// getServerReadTimestamp.
|
|
163
|
+
return newestAcked > 0 ? Math.min(boundaryTs, newestAcked) : 0;
|
|
164
|
+
}
|
|
165
|
+
return newestAcked;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* The value to hand `flushLastViewedToPrivateStore` as `visibleRoomTs`
|
|
170
|
+
* for a room being left, or `undefined` when no boundary applies (the
|
|
171
|
+
* flush then uses its own newest-acked default).
|
|
172
|
+
*
|
|
173
|
+
* Exists so the SERVER write goes through the SAME clamp as the local
|
|
174
|
+
* stamp. Passing the raw redux boundary straight through would bypass
|
|
175
|
+
* `getReadMarkerTimestamp`'s clamp on exactly the path where a bad value
|
|
176
|
+
* is permanent: the private-store merge is forward-only, so a boundary
|
|
177
|
+
* that (through a pending own message's device `date`, or a stale
|
|
178
|
+
* readBoundaries entry) sat ahead of the room's real history would be
|
|
179
|
+
* written verbatim and could never be corrected again (bug #38).
|
|
180
|
+
*/
|
|
181
|
+
function getFlushBoundaryTs(room, heapState, boundaryTs) {
|
|
182
|
+
if (typeof boundaryTs !== 'number' || !Number.isFinite(boundaryTs) || boundaryTs <= 0) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
const clamped = getReadMarkerTimestamp(room, heapState, boundaryTs);
|
|
186
|
+
return clamped > 0 ? clamped : undefined;
|
|
187
|
+
}
|
|
125
188
|
//# sourceMappingURL=getServerReadTimestamp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["_msgSortableMs","require","FUTURE_READ_MARKER_TOLERANCE_MS","exports","getServerReadTimestamp","room","heapState","heapIds","Set","messageHeap","filter","m","id","map","String","failedIds","Object","keys","failedMessages","newest","messages","pending","has","ts","msgSortableMs","lastViewedTimestamp","isCorruptFutureReadMarker","marker","newestAckedMs","Number","isFinite","Date","now","getReadMarkerTimestamp","boundaryTs","newestAcked","Math","min","getFlushBoundaryTs","undefined","clamped"],"sourceRoot":"../../../src","sources":["helpers/getServerReadTimestamp.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -5,6 +5,37 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.insertMessageWithDelimiter = insertMessageWithDelimiter;
|
|
7
7
|
var _dateComparison = require("./dateComparison");
|
|
8
|
+
var _msgSortableMs = require("./msgSortableMs");
|
|
9
|
+
// Robustly resolve a caller-supplied read marker to epoch milliseconds.
|
|
10
|
+
// Callers pass a plain number (the redux read boundary, or a room's
|
|
11
|
+
// lastViewedTimestamp), a Date object (older call sites), or occasionally
|
|
12
|
+
// a numeric string. These are NOT interchangeable through the Date
|
|
13
|
+
// constructor: `new Date(1757000000123)` (a number) reads as epoch-ms,
|
|
14
|
+
// but `new Date("1757000000123")` (a string) is parsed as a date STRING
|
|
15
|
+
// - a bare 13-digit string matches no recognized date format, so the
|
|
16
|
+
// result is silently Invalid Date and every comparison against it is
|
|
17
|
+
// `false`. Try Number() first so a numeric string/number is read as
|
|
18
|
+
// epoch-ms; only fall through to Date parsing for genuine date/ISO
|
|
19
|
+
// strings (e.g. a Date object's own `.toString()`). Never falls back to
|
|
20
|
+
// `Date.now()` - a marker we can't resolve is treated as "no marker",
|
|
21
|
+
// not "now" (bug #38).
|
|
22
|
+
function resolveMarkerMs(marker) {
|
|
23
|
+
if (marker == null) {
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
if (typeof marker === 'number') {
|
|
27
|
+
return Number.isFinite(marker) ? marker : 0;
|
|
28
|
+
}
|
|
29
|
+
const raw = marker.toString();
|
|
30
|
+
if (raw.trim() !== '') {
|
|
31
|
+
const asNumber = Number(raw);
|
|
32
|
+
if (Number.isFinite(asNumber)) {
|
|
33
|
+
return asNumber;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const parsed = Date.parse(raw);
|
|
37
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
38
|
+
}
|
|
8
39
|
function deepMerge(target, source) {
|
|
9
40
|
for (const key in source) {
|
|
10
41
|
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
@@ -53,21 +84,32 @@ function insertMessageWithDelimiter(roomMessages, message, lastViewedTimestamp)
|
|
|
53
84
|
} else {
|
|
54
85
|
roomMessages.push(message);
|
|
55
86
|
}
|
|
56
|
-
|
|
57
|
-
|
|
87
|
+
const lastViewedMs = resolveMarkerMs(lastViewedTimestamp);
|
|
88
|
+
const newMessageMs = (0, _msgSortableMs.msgSortableMs)(message);
|
|
89
|
+
if (lastViewedMs > 0 && newMessageMs > lastViewedMs && !roomMessages.some(msg => msg.id === 'delimiter-new')) {
|
|
90
|
+
// Find the first message STRICTLY newer than the marker, using the
|
|
91
|
+
// SAME timestamp source (msgSortableMs - the server id-encoded ms)
|
|
92
|
+
// as the unread middleware and countNewerMessages use to decide
|
|
93
|
+
// what counts as unread. Comparing against a DIFFERENT source (the
|
|
94
|
+
// old code compared `msg.date` strings) risks the boundary message
|
|
95
|
+
// itself landing on the wrong side of the cut: since bug #38 the
|
|
96
|
+
// marker can equal a real message's own timestamp exactly, and any
|
|
97
|
+
// drift between `date` and the id-encoded ms - or a raw numeric
|
|
98
|
+
// marker silently producing an Invalid Date via the Date
|
|
99
|
+
// constructor's string-parsing path - could count that message as
|
|
100
|
+
// unread, pushing the divider one message too early (ABOVE the
|
|
101
|
+
// last read message instead of directly below it). Customer #42.
|
|
102
|
+
const delimiterIndex = roomMessages.findIndex(msg => msg.id !== 'delimiter-new' && (0, _msgSortableMs.msgSortableMs)(msg) > lastViewedMs);
|
|
58
103
|
if (delimiterIndex !== -1) {
|
|
59
104
|
// The divider's date is what ORDERS it: roomsSlice re-sorts every
|
|
60
105
|
// merged page by timestamp (see `byMs`), so a divider stamped with
|
|
61
|
-
// `new Date()`
|
|
106
|
+
// `new Date()` (i.e. now) sorted past every real message and
|
|
62
107
|
// rendered at the very bottom, BELOW the new messages it is
|
|
63
108
|
// supposed to introduce. Anchor it a hair before the first unread
|
|
64
109
|
// instead, which is where it belongs and where any later sort keeps
|
|
65
|
-
// it.
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const rawLastViewed = lastViewedTimestamp.toString();
|
|
69
|
-
const lastViewedMs = Date.parse(rawLastViewed) || Number(rawLastViewed) || Date.now();
|
|
70
|
-
const anchorMs = Number.isFinite(firstUnreadMs) ? firstUnreadMs - 1 : lastViewedMs;
|
|
110
|
+
// it.
|
|
111
|
+
const firstUnreadMs = (0, _msgSortableMs.msgSortableMs)(roomMessages[delimiterIndex]);
|
|
112
|
+
const anchorMs = firstUnreadMs > 0 ? firstUnreadMs - 1 : lastViewedMs;
|
|
71
113
|
roomMessages.splice(delimiterIndex, 0, {
|
|
72
114
|
id: 'delimiter-new',
|
|
73
115
|
user: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_dateComparison","require","deepMerge","target","source","key","Array","isArray","insertMessageWithDelimiter","roomMessages","message","lastViewedTimestamp","existingIndex","findIndex","msg","id","xmppId","existing","preservedUserId","user","merged","pending","newMessageDate","date","lastMessage","length","firstMessage","isDateAfter","
|
|
1
|
+
{"version":3,"names":["_dateComparison","require","_msgSortableMs","resolveMarkerMs","marker","Number","isFinite","raw","toString","trim","asNumber","parsed","Date","parse","deepMerge","target","source","key","Array","isArray","insertMessageWithDelimiter","roomMessages","message","lastViewedTimestamp","existingIndex","findIndex","msg","id","xmppId","existing","preservedUserId","user","merged","pending","newMessageDate","date","lastMessage","length","firstMessage","isDateAfter","index","push","lastViewedMs","newMessageMs","msgSortableMs","some","delimiterIndex","firstUnreadMs","anchorMs","splice","name","undefined","token","refreshToken","toISOString","body","roomJid","isDateBefore","unshift","i"],"sourceRoot":"../../../src","sources":["helpers/insertMessageWithDelimiter.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -14,7 +14,17 @@ exports.getKeyboardVerticalOffset = getKeyboardVerticalOffset;
|
|
|
14
14
|
const getInputDockPaddingBottom = ({
|
|
15
15
|
platform,
|
|
16
16
|
bottomInset = 0,
|
|
17
|
-
keyboardVisible = false
|
|
18
|
-
|
|
17
|
+
keyboardVisible = false,
|
|
18
|
+
configuredPadding,
|
|
19
|
+
hostOwnsLayout = false
|
|
20
|
+
}) => {
|
|
21
|
+
if (typeof configuredPadding === 'number') {
|
|
22
|
+
return configuredPadding;
|
|
23
|
+
}
|
|
24
|
+
if (hostOwnsLayout) {
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
return platform === 'ios' ? bottomInset : ANDROID_INPUT_DOCK_GAP;
|
|
28
|
+
};
|
|
19
29
|
exports.getInputDockPaddingBottom = getInputDockPaddingBottom;
|
|
20
30
|
//# sourceMappingURL=keyboardLayout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["ANDROID_INPUT_DOCK_GAP","exports","getKeyboardVerticalOffset","platform","configuredOffset","bottomInset","getInputDockPaddingBottom","keyboardVisible"],"sourceRoot":"../../../src","sources":["helpers/keyboardLayout.ts"],"mappings":";;;;;;AAOO,MAAMA,sBAAsB,GAAAC,OAAA,CAAAD,sBAAA,GAAG,EAAE;AAEjC,MAAME,yBAAyB,GAAGA,CAAC;EACxCC,QAAQ;EACRC,gBAAgB,GAAG,CAAC;EACpBC,WAAW,GAAG;AACI,CAAC,KACnBD,gBAAgB,IAAID,QAAQ,KAAK,KAAK,GAAGE,WAAW,GAAG,CAAC,CAAC;AAACJ,OAAA,CAAAC,yBAAA,GAAAA,yBAAA;
|
|
1
|
+
{"version":3,"names":["ANDROID_INPUT_DOCK_GAP","exports","getKeyboardVerticalOffset","platform","configuredOffset","bottomInset","getInputDockPaddingBottom","keyboardVisible","configuredPadding","hostOwnsLayout"],"sourceRoot":"../../../src","sources":["helpers/keyboardLayout.ts"],"mappings":";;;;;;AAOO,MAAMA,sBAAsB,GAAAC,OAAA,CAAAD,sBAAA,GAAG,EAAE;AAEjC,MAAME,yBAAyB,GAAGA,CAAC;EACxCC,QAAQ;EACRC,gBAAgB,GAAG,CAAC;EACpBC,WAAW,GAAG;AACI,CAAC,KACnBD,gBAAgB,IAAID,QAAQ,KAAK,KAAK,GAAGE,WAAW,GAAG,CAAC,CAAC;AAACJ,OAAA,CAAAC,yBAAA,GAAAA,yBAAA;AAcrD,MAAMI,yBAAyB,GAAGA,CAAC;EACxCH,QAAQ;EACRE,WAAW,GAAG,CAAC;EACfE,eAAe,GAAG,KAAK;EACvBC,iBAAiB;EACjBC,cAAc,GAAG;AACG,CAAC,KAAa;EAClC,IAAI,OAAOD,iBAAiB,KAAK,QAAQ,EAAE;IACzC,OAAOA,iBAAiB;EAC1B;EACA,IAAIC,cAAc,EAAE;IAClB,OAAO,CAAC;EACV;EACA,OAAON,QAAQ,KAAK,KAAK,GAAGE,WAAW,GAAGL,sBAAsB;AAClE,CAAC;AAACC,OAAA,CAAAK,yBAAA,GAAAA,yBAAA","ignoreList":[]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.msgSortableMs = void 0;
|
|
7
|
+
// Count messages strictly newer than a given millisecond timestamp using
|
|
8
|
+
// `msg.id` (the server-authoritative microsecond timestamp prefixed by a
|
|
9
|
+
// 13-digit millis, see `helpers/dateComparison`'s
|
|
10
|
+
// `getHighResolutionTimestamp`) rather than `msg.date`, which can be
|
|
11
|
+
// derived client-side (`createMessageFromXml` falls back to `Date.now()`
|
|
12
|
+
// for realtime stanzas without a `date` attr) and drift from what the
|
|
13
|
+
// server actually assigned.
|
|
14
|
+
//
|
|
15
|
+
// Extracted to its own module (rather than living in roomsSlice.ts, its
|
|
16
|
+
// original home) so helpers that need the SAME ordering source - notably
|
|
17
|
+
// `insertMessageWithDelimiter.ts`, which decides where the "New messages"
|
|
18
|
+
// divider sits - can import it without creating a roomStore <-> helpers
|
|
19
|
+
// import cycle (roomsSlice.ts already imports insertMessageWithDelimiter).
|
|
20
|
+
// roomsSlice.ts re-exports this for backward compatibility with existing
|
|
21
|
+
// call sites.
|
|
22
|
+
const msgSortableMs = msg => {
|
|
23
|
+
const id = String(msg?.id || '');
|
|
24
|
+
const m = /^(\d{13})/.exec(id);
|
|
25
|
+
if (m) {
|
|
26
|
+
return Number(m[1]);
|
|
27
|
+
}
|
|
28
|
+
if (msg?.date) {
|
|
29
|
+
const t = new Date(msg.date).getTime();
|
|
30
|
+
if (Number.isFinite(t)) {
|
|
31
|
+
return t;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return 0;
|
|
35
|
+
};
|
|
36
|
+
exports.msgSortableMs = msgSortableMs;
|
|
37
|
+
//# sourceMappingURL=msgSortableMs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["msgSortableMs","msg","id","String","m","exec","Number","date","t","Date","getTime","isFinite","exports"],"sourceRoot":"../../../src","sources":["helpers/msgSortableMs.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,aAAa,GAAIC,GAAQ,IAAa;EACjD,MAAMC,EAAE,GAAGC,MAAM,CAACF,GAAG,EAAEC,EAAE,IAAI,EAAE,CAAC;EAChC,MAAME,CAAC,GAAG,WAAW,CAACC,IAAI,CAACH,EAAE,CAAC;EAC9B,IAAIE,CAAC,EAAE;IAAC,OAAOE,MAAM,CAACF,CAAC,CAAC,CAAC,CAAC,CAAC;EAAC;EAC5B,IAAIH,GAAG,EAAEM,IAAI,EAAE;IACb,MAAMC,CAAC,GAAG,IAAIC,IAAI,CAACR,GAAG,CAACM,IAAW,CAAC,CAACG,OAAO,CAAC,CAAC;IAC7C,IAAIJ,MAAM,CAACK,QAAQ,CAACH,CAAC,CAAC,EAAE;MAAC,OAAOA,CAAC;IAAC;EACpC;EACA,OAAO,CAAC;AACV,CAAC;AAACI,OAAA,CAAAZ,aAAA,GAAAA,aAAA","ignoreList":[]}
|
|
@@ -47,12 +47,27 @@ const useChatRoomFocus = ({
|
|
|
47
47
|
roomJID: null,
|
|
48
48
|
isFocused: false
|
|
49
49
|
});
|
|
50
|
-
|
|
50
|
+
|
|
51
|
+
// `clearBoundary`: pass true only when the room the user is leaving is
|
|
52
|
+
// genuinely being released (switching to a different room, or this
|
|
53
|
+
// hook unmounting) - not on a mere same-room blur. `<ChatRoom>`'s
|
|
54
|
+
// MessageList typically stays mounted across a same-room focus loss
|
|
55
|
+
// (the whole point of this hook is that the host keeps `<Chat>`
|
|
56
|
+
// mounted in a hidden tab), so its own scroll-tracking ref is still
|
|
57
|
+
// intact and the redux boundary must stay in sync with it - clearing
|
|
58
|
+
// it here would desync the two.
|
|
59
|
+
const leaveRoom = (jid, clearBoundary) => {
|
|
51
60
|
const state = _roomStore.store.getState();
|
|
52
61
|
const rooms = state.rooms?.rooms;
|
|
53
|
-
const
|
|
54
|
-
//
|
|
55
|
-
//
|
|
62
|
+
const boundaryTs = state.rooms?.readBoundaries?.[jid] ?? null;
|
|
63
|
+
// getReadMarkerTimestamp: honour the boundary (the newest message the
|
|
64
|
+
// user actually reached) when the user left this room scrolled up,
|
|
65
|
+
// otherwise fall back to the newest server-acked message. Only stamp
|
|
66
|
+
// when we actually have something to anchor to - skip rather than
|
|
67
|
+
// fall back to the device clock (bug #38). Ignoring the boundary here
|
|
68
|
+
// would stamp "everything read" regardless of scroll position (bug
|
|
69
|
+
// #42, a regression of #33 reintroduced by #38).
|
|
70
|
+
const timestamp = (0, _getServerReadTimestamp.getReadMarkerTimestamp)(rooms?.[jid], state.roomHeapSlice, boundaryTs);
|
|
56
71
|
if (timestamp > 0) {
|
|
57
72
|
dispatch((0, _roomsSlice.setLastViewedTimestamp)({
|
|
58
73
|
chatJID: jid,
|
|
@@ -61,13 +76,22 @@ const useChatRoomFocus = ({
|
|
|
61
76
|
}
|
|
62
77
|
dispatch((0, _roomsSlice.clearVisibleRoom)());
|
|
63
78
|
state.chatSettingStore?.client?.flushLastViewedToPrivateStoreStanza(rooms, {
|
|
64
|
-
visibleRoomJID: jid
|
|
79
|
+
visibleRoomJID: jid,
|
|
80
|
+
// Carry the same boundary to the SERVER marker - without it the
|
|
81
|
+
// flush defaults to "everything" for the visible room. Clamped
|
|
82
|
+
// through the same helper as the local stamp above.
|
|
83
|
+
visibleRoomTs: (0, _getServerReadTimestamp.getFlushBoundaryTs)(rooms?.[jid], state.roomHeapSlice, boundaryTs)
|
|
65
84
|
}).catch(() => {});
|
|
85
|
+
if (clearBoundary) {
|
|
86
|
+
dispatch((0, _roomsSlice.clearReadBoundary)({
|
|
87
|
+
jid
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
66
90
|
};
|
|
67
91
|
(0, _react.useEffect)(() => {
|
|
68
92
|
const prev = prevRef.current;
|
|
69
93
|
if (prev.isFocused && prev.roomJID && (prev.roomJID !== roomJID || !isFocused)) {
|
|
70
|
-
leaveRoom(prev.roomJID);
|
|
94
|
+
leaveRoom(prev.roomJID, prev.roomJID !== roomJID);
|
|
71
95
|
}
|
|
72
96
|
if (roomJID && isFocused) {
|
|
73
97
|
dispatch((0, _roomsSlice.setCurrentRoom)({
|
|
@@ -86,7 +110,7 @@ const useChatRoomFocus = ({
|
|
|
86
110
|
return () => {
|
|
87
111
|
const prev = prevRef.current;
|
|
88
112
|
if (prev.isFocused && prev.roomJID) {
|
|
89
|
-
leaveRoom(prev.roomJID);
|
|
113
|
+
leaveRoom(prev.roomJID, true);
|
|
90
114
|
}
|
|
91
115
|
};
|
|
92
116
|
}, []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","require","_reactRedux","_roomsSlice","_roomStore","_getServerReadTimestamp","useChatRoomFocus","roomJID","isFocused","dispatch","useDispatch","prevRef","useRef","leaveRoom","jid","state","store","getState","rooms","timestamp","
|
|
1
|
+
{"version":3,"names":["_react","require","_reactRedux","_roomsSlice","_roomStore","_getServerReadTimestamp","useChatRoomFocus","roomJID","isFocused","dispatch","useDispatch","prevRef","useRef","leaveRoom","jid","clearBoundary","state","store","getState","rooms","boundaryTs","readBoundaries","timestamp","getReadMarkerTimestamp","roomHeapSlice","setLastViewedTimestamp","chatJID","clearVisibleRoom","chatSettingStore","client","flushLastViewedToPrivateStoreStanza","visibleRoomJID","visibleRoomTs","getFlushBoundaryTs","catch","clearReadBoundary","useEffect","prev","current","setCurrentRoom","setVisibleRoom","exports","_default","default"],"sourceRoot":"../../../src","sources":["hooks/useChatRoomFocus.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -16,6 +16,7 @@ var _pushSubscriptionService = require("../services/pushSubscriptionService");
|
|
|
16
16
|
var _rooms = require("../networking/api-requests/rooms.api");
|
|
17
17
|
var _persistence = require("../roomStore/persistence");
|
|
18
18
|
var _secureUserStorage = require("../helpers/secureUserStorage");
|
|
19
|
+
var _getServerReadTimestamp = require("../helpers/getServerReadTimestamp");
|
|
19
20
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
21
|
// AsyncStorage keys the library writes but that aren't cleared by any
|
|
21
22
|
// slice reducer. Listed here so a single logout call wipes the full
|
|
@@ -63,9 +64,16 @@ const logoutService = exports.logoutService = {
|
|
|
63
64
|
const client = state.chatSettingStore?.client;
|
|
64
65
|
const rooms = state.rooms?.rooms;
|
|
65
66
|
const visibleRoomJID = state.rooms?.visibleRoomJID || null;
|
|
67
|
+
// The visible room is exempt from `onlyIfNoUnread`'s skip (it's
|
|
68
|
+
// meant to write "read up to now" for whatever's open), so if the
|
|
69
|
+
// user is logging out while scrolled up with unread messages
|
|
70
|
+
// above, the boundary must still be carried through here - same
|
|
71
|
+
// reasoning as every other "leaving a room" path (bug #42).
|
|
72
|
+
const boundaryTs = visibleRoomJID ? (0, _getServerReadTimestamp.getFlushBoundaryTs)(rooms?.[visibleRoomJID], state.roomHeapSlice, state.rooms?.readBoundaries?.[visibleRoomJID] ?? null) : undefined;
|
|
66
73
|
if (client?.flushLastViewedToPrivateStoreStanza) {
|
|
67
74
|
await Promise.race([client.flushLastViewedToPrivateStoreStanza(rooms, {
|
|
68
75
|
visibleRoomJID,
|
|
76
|
+
visibleRoomTs: boundaryTs,
|
|
69
77
|
onlyIfNoUnread: true
|
|
70
78
|
}), new Promise(res => setTimeout(res, 2000))]);
|
|
71
79
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactRedux","require","_reactNative","_asyncStorage","_interopRequireDefault","_roomStore","_chatSettingsSlice","_roomsSlice","_react","_roomHeapSlice","_pushSubscriptionService","_rooms","_persistence","_secureUserStorage","e","__esModule","default","LIBRARY_STRAY_KEYS","logoutService","exports","performLogout","state","store","getState","client","chatSettingStore","rooms","visibleRoomJID","flushLastViewedToPrivateStoreStanza","Promise","race","onlyIfNoUnread","res","setTimeout","console","warn","DeviceEventEmitter","emit","pushSubscriptionService","reset","clearRoomsRestCache","dispatch","setLogoutState","clearHeap","logout","clearPersistedState","AsyncStorage","multiRemove","secureUserStorage","remove","useLogout","useDispatch","useCallback","err"],"sourceRoot":"../../../src","sources":["hooks/useLogout.tsx"],"mappings":";;;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,aAAA,GAAAC,sBAAA,CAAAH,OAAA;AACA,IAAAI,UAAA,GAAAJ,OAAA;AACA,IAAAK,kBAAA,GAAAL,OAAA;AACA,IAAAM,WAAA,GAAAN,OAAA;AACA,IAAAO,MAAA,GAAAP,OAAA;AACA,IAAAQ,cAAA,GAAAR,OAAA;AACA,IAAAS,wBAAA,GAAAT,OAAA;AACA,IAAAU,MAAA,GAAAV,OAAA;AACA,IAAAW,YAAA,GAAAX,OAAA;AACA,IAAAY,kBAAA,GAAAZ,OAAA;
|
|
1
|
+
{"version":3,"names":["_reactRedux","require","_reactNative","_asyncStorage","_interopRequireDefault","_roomStore","_chatSettingsSlice","_roomsSlice","_react","_roomHeapSlice","_pushSubscriptionService","_rooms","_persistence","_secureUserStorage","_getServerReadTimestamp","e","__esModule","default","LIBRARY_STRAY_KEYS","logoutService","exports","performLogout","state","store","getState","client","chatSettingStore","rooms","visibleRoomJID","boundaryTs","getFlushBoundaryTs","roomHeapSlice","readBoundaries","undefined","flushLastViewedToPrivateStoreStanza","Promise","race","visibleRoomTs","onlyIfNoUnread","res","setTimeout","console","warn","DeviceEventEmitter","emit","pushSubscriptionService","reset","clearRoomsRestCache","dispatch","setLogoutState","clearHeap","logout","clearPersistedState","AsyncStorage","multiRemove","secureUserStorage","remove","useLogout","useDispatch","useCallback","err"],"sourceRoot":"../../../src","sources":["hooks/useLogout.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -3,9 +3,17 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.mergeUsersSet = exports.editRoomMessage = exports.deleteRoomMessage = exports.deleteRoom = exports.deleteAllRooms = exports.default = exports.clearVisibleRoom = exports.clearReadBoundary = exports.clearPendingNotificationJid = exports.applyRoomsPreloadBatch = exports.applyPrivateStoreMarkers = exports.addRoomViaApi = exports.addRoomMessage = exports.addRoom = exports.RUNTIME_MESSAGE_LIMIT = void 0;
|
|
7
|
+
Object.defineProperty(exports, "msgSortableMs", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () {
|
|
10
|
+
return _msgSortableMs.msgSortableMs;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
exports.updateRoom = exports.setVisibleRoom = exports.setUnreadSyncing = exports.setRoomRole = exports.setRoomNoMessages = exports.setRoomMessages = exports.setReadBoundary = exports.setReactions = exports.setPendingNotificationJid = exports.setLogoutState = exports.setLastViewedTimestamp = exports.setIsLoading = exports.setEditAction = exports.setCurrentRoom = exports.setComposing = exports.setCloseActiveMessage = exports.setActiveMessage = exports.roomsStore = void 0;
|
|
7
14
|
var _toolkit = require("@reduxjs/toolkit");
|
|
8
15
|
var _insertMessageWithDelimiter = require("../helpers/insertMessageWithDelimiter");
|
|
16
|
+
var _msgSortableMs = require("../helpers/msgSortableMs");
|
|
9
17
|
// Per-room runtime message cap. Mirrors the persistence layer's
|
|
10
18
|
// MESSAGE_LIMIT so what's in memory matches what's on disk; otherwise
|
|
11
19
|
// long sessions grow the array unbounded (memory leak) and reload
|
|
@@ -160,7 +168,7 @@ function mergeHistoryIntoCache(existing, fetched) {
|
|
|
160
168
|
}
|
|
161
169
|
}
|
|
162
170
|
const pending = ex.filter(m => m?.pending && !fetchedKeys.has(String(m.id)) && !(m.xmppId && fetchedKeys.has(String(m.xmppId))));
|
|
163
|
-
const byMs = (a, b) => msgSortableMs(a) - msgSortableMs(b);
|
|
171
|
+
const byMs = (a, b) => (0, _msgSortableMs.msgSortableMs)(a) - (0, _msgSortableMs.msgSortableMs)(b);
|
|
164
172
|
const capTail = arr => arr.length > RUNTIME_MESSAGE_LIMIT ? arr.slice(-RUNTIME_MESSAGE_LIMIT) : arr;
|
|
165
173
|
const existingIds = new Set(realExisting.map(m => String(m.id)));
|
|
166
174
|
const overlaps = realFetched.some(m => existingIds.has(String(m.id)));
|
|
@@ -203,7 +211,8 @@ const initialState = {
|
|
|
203
211
|
text: ''
|
|
204
212
|
},
|
|
205
213
|
pendingNotificationJid: null,
|
|
206
|
-
privateStoreMarkers: {}
|
|
214
|
+
privateStoreMarkers: {},
|
|
215
|
+
readBoundaries: {}
|
|
207
216
|
};
|
|
208
217
|
const isValidRoomJid = jid => {
|
|
209
218
|
if (typeof jid !== 'string' || !jid) return false;
|
|
@@ -448,7 +457,7 @@ const reducers = {
|
|
|
448
457
|
roomMessages.unshift(message);
|
|
449
458
|
} else {
|
|
450
459
|
const lastViewedValue = state.rooms[roomJID].lastViewedTimestamp;
|
|
451
|
-
const lastViewedTimestamp = state.visibleRoomJID === roomJID ? null : lastViewedValue ?
|
|
460
|
+
const lastViewedTimestamp = state.visibleRoomJID === roomJID ? null : lastViewedValue ? lastViewedValue : null;
|
|
452
461
|
(0, _insertMessageWithDelimiter.insertMessageWithDelimiter)(roomMessages, message, lastViewedTimestamp);
|
|
453
462
|
}
|
|
454
463
|
|
|
@@ -464,6 +473,7 @@ const reducers = {
|
|
|
464
473
|
state.rooms = {};
|
|
465
474
|
state.visibleRoomJID = null;
|
|
466
475
|
state.privateStoreMarkers = {};
|
|
476
|
+
state.readBoundaries = {};
|
|
467
477
|
state.isUnreadSyncing = false;
|
|
468
478
|
},
|
|
469
479
|
setComposing(state, action) {
|
|
@@ -578,6 +588,44 @@ const reducers = {
|
|
|
578
588
|
}
|
|
579
589
|
}
|
|
580
590
|
},
|
|
591
|
+
/**
|
|
592
|
+
* Set (or clear) the "read up to here, but not further" boundary for
|
|
593
|
+
* a room - see `readBoundaries` on `RoomMessagesState` for the full
|
|
594
|
+
* contract. `ts` is the msgSortableMs of the newest message the user
|
|
595
|
+
* actually reached before scrolling away from the bottom; `null`/`0`
|
|
596
|
+
* clears it (the user is at the bottom, or nothing was reached yet).
|
|
597
|
+
*/
|
|
598
|
+
setReadBoundary: (state, action) => {
|
|
599
|
+
const {
|
|
600
|
+
jid,
|
|
601
|
+
ts
|
|
602
|
+
} = action.payload;
|
|
603
|
+
if (!jid) {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
if (!state.readBoundaries) {
|
|
607
|
+
state.readBoundaries = {};
|
|
608
|
+
}
|
|
609
|
+
if (typeof ts === 'number' && Number.isFinite(ts) && ts > 0) {
|
|
610
|
+
state.readBoundaries[jid] = ts;
|
|
611
|
+
} else {
|
|
612
|
+
delete state.readBoundaries[jid];
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
/**
|
|
616
|
+
* Release a room's read boundary once it has been consumed by a
|
|
617
|
+
* genuine "leave" (ChatRoom unmount, or a tab-navigator focus hook
|
|
618
|
+
* switching to a different room) - see `readBoundaries` for why the
|
|
619
|
+
* background/`isVisible=false` paths deliberately do NOT call this.
|
|
620
|
+
*/
|
|
621
|
+
clearReadBoundary: (state, action) => {
|
|
622
|
+
const {
|
|
623
|
+
jid
|
|
624
|
+
} = action.payload;
|
|
625
|
+
if (jid && state.readBoundaries) {
|
|
626
|
+
delete state.readBoundaries[jid];
|
|
627
|
+
}
|
|
628
|
+
},
|
|
581
629
|
setRoomRole: (state, action) => {
|
|
582
630
|
const {
|
|
583
631
|
chatJID,
|
|
@@ -657,6 +705,7 @@ const reducers = {
|
|
|
657
705
|
state.isLoading = false;
|
|
658
706
|
state.isUnreadSyncing = false;
|
|
659
707
|
state.privateStoreMarkers = {};
|
|
708
|
+
state.readBoundaries = {};
|
|
660
709
|
},
|
|
661
710
|
setActiveMessage: (state, action) => {
|
|
662
711
|
const {
|
|
@@ -759,32 +808,13 @@ const roomsStore = exports.roomsStore = (0, _toolkit.createSlice)({
|
|
|
759
808
|
reducers
|
|
760
809
|
});
|
|
761
810
|
|
|
762
|
-
//
|
|
763
|
-
//
|
|
764
|
-
//
|
|
765
|
-
//
|
|
766
|
-
//
|
|
767
|
-
//
|
|
768
|
-
|
|
769
|
-
// user's own messages (parity with unreadMiddleware's isOwnMessage
|
|
770
|
-
// filter — without this, the reducer and the middleware disagree about
|
|
771
|
-
// the count and we get a flicker as the badge gets written twice with
|
|
772
|
-
// different values on every message).
|
|
773
|
-
const msgSortableMs = msg => {
|
|
774
|
-
const id = String(msg?.id || '');
|
|
775
|
-
const m = /^(\d{13})/.exec(id);
|
|
776
|
-
if (m) {
|
|
777
|
-
return Number(m[1]);
|
|
778
|
-
}
|
|
779
|
-
if (msg?.date) {
|
|
780
|
-
const t = new Date(msg.date).getTime();
|
|
781
|
-
if (Number.isFinite(t)) {
|
|
782
|
-
return t;
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
return 0;
|
|
786
|
-
};
|
|
787
|
-
exports.msgSortableMs = msgSortableMs;
|
|
811
|
+
// Re-exported for backward compatibility - every existing call site
|
|
812
|
+
// imports `msgSortableMs` from here. The implementation now lives in
|
|
813
|
+
// helpers/msgSortableMs.ts (imported above), so insertMessageWithDelimiter.ts
|
|
814
|
+
// (which this file itself imports) can use the SAME ordering source
|
|
815
|
+
// without a roomStore <-> helpers import cycle. See that file for the
|
|
816
|
+
// full rationale (server id vs. client `date`).
|
|
817
|
+
|
|
788
818
|
const norm = s => {
|
|
789
819
|
if (s == null) {
|
|
790
820
|
return '';
|
|
@@ -832,7 +862,7 @@ const newestAckedMessageMs = messages => {
|
|
|
832
862
|
if (!m || m.id === 'delimiter-new' || m.pending) {
|
|
833
863
|
continue;
|
|
834
864
|
}
|
|
835
|
-
const ms = msgSortableMs(m);
|
|
865
|
+
const ms = (0, _msgSortableMs.msgSortableMs)(m);
|
|
836
866
|
if (ms > newest) {
|
|
837
867
|
newest = ms;
|
|
838
868
|
}
|
|
@@ -851,7 +881,7 @@ const countNewerMessages = (messages, timestamp, selfXmpp = '', selfWallet = '')
|
|
|
851
881
|
if (isOwn(message, selfXmpp, selfWallet)) {
|
|
852
882
|
continue;
|
|
853
883
|
}
|
|
854
|
-
const ms = msgSortableMs(message);
|
|
884
|
+
const ms = (0, _msgSortableMs.msgSortableMs)(message);
|
|
855
885
|
if (Number.isFinite(ms) && ms > timestamp) {
|
|
856
886
|
count += 1;
|
|
857
887
|
}
|
|
@@ -871,6 +901,8 @@ const {
|
|
|
871
901
|
setUnreadSyncing,
|
|
872
902
|
setLastViewedTimestamp,
|
|
873
903
|
applyPrivateStoreMarkers,
|
|
904
|
+
setReadBoundary,
|
|
905
|
+
clearReadBoundary,
|
|
874
906
|
setRoomNoMessages,
|
|
875
907
|
setCurrentRoom,
|
|
876
908
|
setVisibleRoom,
|
|
@@ -902,6 +934,8 @@ exports.clearVisibleRoom = clearVisibleRoom;
|
|
|
902
934
|
exports.setVisibleRoom = setVisibleRoom;
|
|
903
935
|
exports.setCurrentRoom = setCurrentRoom;
|
|
904
936
|
exports.setRoomNoMessages = setRoomNoMessages;
|
|
937
|
+
exports.clearReadBoundary = clearReadBoundary;
|
|
938
|
+
exports.setReadBoundary = setReadBoundary;
|
|
905
939
|
exports.applyPrivateStoreMarkers = applyPrivateStoreMarkers;
|
|
906
940
|
exports.setLastViewedTimestamp = setLastViewedTimestamp;
|
|
907
941
|
exports.setUnreadSyncing = setUnreadSyncing;
|