Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3266613
D11328.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
6 KB
Referenced Files
None
Subscribers
None
D11328.diff
View Options
diff --git a/web/push-notif/badge-handler.react.js b/web/push-notif/badge-handler.react.js
--- a/web/push-notif/badge-handler.react.js
+++ b/web/push-notif/badge-handler.react.js
@@ -2,35 +2,59 @@
import * as React from 'react';
-import { connectionSelector } from 'lib/selectors/keyserver-selectors.js';
-import { unreadCount } from 'lib/selectors/thread-selectors.js';
-import type { ConnectionInfo } from 'lib/types/socket-types.js';
+import { allConnectionInfosSelector } from 'lib/selectors/keyserver-selectors.js';
+import { allUnreadCounts } from 'lib/selectors/thread-selectors.js';
-import { authoritativeKeyserverID } from '../authoritative-keyserver.js';
+import {
+ updateNotifsUnreadCountStorage,
+ queryNotifsUnreadCountStorage,
+} from './notif-crypto-utils.js';
import electron from '../electron.js';
import { useSelector } from '../redux/redux-utils.js';
import getTitle from '../title/get-title.js';
function useBadgeHandler() {
- const connection = useSelector(connectionSelector(authoritativeKeyserverID));
- const prevConnection = React.useRef<?ConnectionInfo>();
-
- const boundUnreadCount = useSelector(unreadCount);
- const prevUnreadCount = React.useRef(boundUnreadCount);
+ const connection = useSelector(allConnectionInfosSelector);
+ const unreadCount = useSelector(allUnreadCounts);
React.useEffect(() => {
- if (
- connection?.status === 'connected' &&
- (prevConnection.current?.status !== 'connected' ||
- boundUnreadCount !== prevUnreadCount.current)
- ) {
- document.title = getTitle(boundUnreadCount);
- electron?.setBadge(boundUnreadCount === 0 ? null : boundUnreadCount);
- }
-
- prevConnection.current = connection;
- prevUnreadCount.current = boundUnreadCount;
- }, [boundUnreadCount, connection]);
+ void (async () => {
+ const unreadCountUpdates: {
+ [keyserverID: string]: number,
+ } = {};
+ const unreadCountQueries: Array<string> = [];
+
+ for (const keyserverID in unreadCount) {
+ if (connection[keyserverID]?.status !== 'connected') {
+ unreadCountQueries.push(keyserverID);
+ continue;
+ }
+ unreadCountUpdates[keyserverID] = unreadCount[keyserverID];
+ }
+
+ let queriedUnreadCounts: { +[keyserverID: string]: ?number } = {};
+ [queriedUnreadCounts] = await Promise.all([
+ queryNotifsUnreadCountStorage(unreadCountQueries),
+ updateNotifsUnreadCountStorage(unreadCountUpdates),
+ ]);
+
+ let totalUnreadCount = 0;
+ for (const keyserverID in unreadCountUpdates) {
+ totalUnreadCount += unreadCountUpdates[keyserverID];
+ }
+
+ for (const keyserverID in queriedUnreadCounts) {
+ if (!queriedUnreadCounts[keyserverID]) {
+ totalUnreadCount += unreadCount[keyserverID];
+ continue;
+ }
+ totalUnreadCount += queriedUnreadCounts[keyserverID];
+ }
+
+ document.title = getTitle(totalUnreadCount);
+ electron?.setBadge(totalUnreadCount === 0 ? null : totalUnreadCount);
+ })();
+ }, [unreadCount, connection]);
}
export default useBadgeHandler;
diff --git a/web/push-notif/notif-crypto-utils.js b/web/push-notif/notif-crypto-utils.js
--- a/web/push-notif/notif-crypto-utils.js
+++ b/web/push-notif/notif-crypto-utils.js
@@ -58,6 +58,8 @@
const ASHOAT_KEYSERVER_ID_USED_ONLY_FOR_MIGRATION_FROM_LEGACY_NOTIF_STORAGE =
'256';
+const INDEXED_DB_UNREAD_COUNT_SUFFIX = 'unreadCount';
+
async function decryptWebNotification(
encryptedNotification: EncryptedWebNotification,
): Promise<PlainTextWebNotification | WebNotifDecryptionError> {
@@ -105,6 +107,11 @@
encryptedPayload,
);
+ const { unreadCount } = decryptedNotification;
+ await updateNotifsUnreadCountStorage({
+ [keyserverID]: unreadCount,
+ });
+
return { id, ...decryptedNotification };
} catch (e) {
return {
@@ -146,8 +153,9 @@
};
}
+ let decryptedNotification;
try {
- return await commonDecrypt(
+ decryptedNotification = await commonDecrypt<{ +[string]: mixed }>(
encryptedOlmData,
olmDataContentKey,
encryptionKey,
@@ -159,6 +167,27 @@
staffCanSee,
};
}
+
+ if (!keyserverID) {
+ return decryptedNotification;
+ }
+
+ // iOS notifications require that unread count is set under
+ // `badge` key. Since MacOS notifications are created by the
+ // same function the unread count is also set under `badge` key
+ const { badge } = decryptedNotification;
+ if (typeof badge === 'number') {
+ await updateNotifsUnreadCountStorage({ [(keyserverID: string)]: badge });
+ return decryptedNotification;
+ }
+
+ const { unreadCount } = decryptedNotification;
+ if (typeof unreadCount === 'number') {
+ await updateNotifsUnreadCountStorage({
+ [(keyserverID: string)]: unreadCount,
+ });
+ }
+ return decryptedNotification;
}
async function commonDecrypt<T>(
@@ -463,10 +492,53 @@
await Promise.all([...insertionPromises, ...deletionPromises]);
}
+// Multiple keyserver unread count utilities
+function getKeyserverUnreadCountKey(keyserverID: string) {
+ return [
+ INDEXED_DB_KEYSERVER_PREFIX,
+ keyserverID,
+ INDEXED_DB_UNREAD_COUNT_SUFFIX,
+ ].join(INDEXED_DB_KEY_SEPARATOR);
+}
+
+async function updateNotifsUnreadCountStorage(perKeyserverUnreadCount: {
+ +[keyserverID: string]: number,
+}) {
+ const unreadCountUpdatePromises: Array<Promise<number>> = Object.entries(
+ perKeyserverUnreadCount,
+ ).map(([keyserverID, unreadCount]) => {
+ const keyserverUnreadCountKey = getKeyserverUnreadCountKey(keyserverID);
+ return localforage.setItem<number>(keyserverUnreadCountKey, unreadCount);
+ });
+
+ await Promise.all(unreadCountUpdatePromises);
+}
+
+async function queryNotifsUnreadCountStorage(
+ keyserverIDs: $ReadOnlyArray<string>,
+): Promise<{
+ +[keyserverID: string]: ?number,
+}> {
+ const queryUnreadCountPromises: Array<Promise<[string, ?number]>> =
+ keyserverIDs.map(async keyserverID => {
+ const keyserverUnreadCountKey = getKeyserverUnreadCountKey(keyserverID);
+ const unreadCount = await localforage.getItem<number>(
+ keyserverUnreadCountKey,
+ );
+ return [keyserverID, unreadCount];
+ });
+
+ const queriedUnreadCounts: $ReadOnlyArray<[string, ?number]> =
+ await Promise.all(queryUnreadCountPromises);
+ return Object.fromEntries(queriedUnreadCounts);
+}
+
export {
decryptWebNotification,
decryptDesktopNotification,
getOlmDataContentKeyForCookie,
getOlmEncryptionKeyDBLabelForCookie,
migrateLegacyOlmNotificationsSessions,
+ updateNotifsUnreadCountStorage,
+ queryNotifsUnreadCountStorage,
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 17, 2:12 AM (21 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2510598
Default Alt Text
D11328.diff (6 KB)
Attached To
Mode
D11328: Implement multiple keyserver unread count on web and desktop on top of IndexedDB
Attached
Detach File
Event Timeline
Log In to Comment