Page MenuHomePhabricator

D13210.id43814.diff
No OneTemporary

D13210.id43814.diff

diff --git a/lib/selectors/thread-selectors.js b/lib/selectors/thread-selectors.js
--- a/lib/selectors/thread-selectors.js
+++ b/lib/selectors/thread-selectors.js
@@ -18,7 +18,7 @@
} from './calendar-filter-selectors.js';
import { relativeMemberInfoSelectorForMembersOfThread } from './user-selectors.js';
import genesis from '../facts/genesis.js';
-import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
import {
getAvatarForThread,
getRandomDefaultEmojiAvatar,
@@ -263,10 +263,14 @@
} = createSelector(
(state: BaseAppState<>) => state.threadStore.threadInfos,
(threadInfos: RawThreadInfos): { +[keyserverID: string]: number } => {
+ const thinThreadInfosList = values(threadInfos).filter(
+ threadInfo => !threadInfo.thick,
+ );
+
const keyserverToThreads = _groupBy(threadInfo =>
- extractKeyserverIDFromIDOptional(threadInfo.id),
+ extractKeyserverIDFromID(threadInfo.id),
)(
- values(threadInfos).filter(threadInfo =>
+ thinThreadInfosList.filter(threadInfo =>
threadInHomeChatList(threadInfo),
),
);
diff --git a/web/app.react.js b/web/app.react.js
--- a/web/app.react.js
+++ b/web/app.react.js
@@ -69,7 +69,7 @@
import UpdateModalHandler from './modals/update-modal.react.js';
import SettingsSwitcher from './navigation-panels/settings-switcher.react.js';
import Topbar from './navigation-panels/topbar.react.js';
-import useBadgeHandler from './push-notif/badge-handler.react.js';
+import BadgeHandler from './push-notif/badge-handler.react.js';
import encryptedNotifUtilsAPI from './push-notif/encrypted-notif-utils-api.js';
import { PushNotificationsHandler } from './push-notif/push-notifs-handler.js';
import { updateNavInfoActionType } from './redux/action-types.js';
@@ -532,8 +532,6 @@
!!state.threadStore.threadInfos[activeChatThreadID]?.currentUser.unread,
);
- useBadgeHandler();
-
const dispatch = useDispatch();
const modalContext = useModalContext();
const modals = React.useMemo(
@@ -561,6 +559,7 @@
onClose={releaseLockOrAbortRequest}
secondaryTunnelbrokerConnection={secondaryTunnelbrokerConnection}
>
+ <BadgeHandler />
<IdentitySearchProvider>
<QRAuthProvider
parseTunnelbrokerQRAuthMessage={parseTunnelbrokerQRAuthMessage}
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
@@ -3,11 +3,17 @@
import * as React from 'react';
import { allConnectionInfosSelector } from 'lib/selectors/keyserver-selectors.js';
-import { allUnreadCounts } from 'lib/selectors/thread-selectors.js';
+import {
+ allUnreadCounts,
+ unreadThickThreadIDsSelector,
+} from 'lib/selectors/thread-selectors.js';
+import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js';
import {
updateNotifsUnreadCountStorage,
queryNotifsUnreadCountStorage,
+ getNotifsUnreadThickThreadIDs,
+ updateNotifsUnreadThickThreadIDsStorage,
} from './notif-crypto-utils.js';
import electron from '../electron.js';
import { useSelector } from '../redux/redux-utils.js';
@@ -17,6 +23,9 @@
const connection = useSelector(allConnectionInfosSelector);
const unreadCount = useSelector(allUnreadCounts);
+ const { socketState: tunnelbrokerSocketState } = useTunnelbroker();
+ const currentUnreadThickThreadIDs = useSelector(unreadThickThreadIDsSelector);
+
React.useEffect(() => {
void (async () => {
const unreadCountUpdates: {
@@ -33,8 +42,23 @@
}
let queriedUnreadCounts: { +[keyserverID: string]: ?number } = {};
- [queriedUnreadCounts] = await Promise.all([
+ let unreadThickThreadIDs: $ReadOnlyArray<string> = [];
+
+ const handleUnreadThickThreadIDsInNotifsStoragePromise = (async () => {
+ if (tunnelbrokerSocketState.connected) {
+ await updateNotifsUnreadThickThreadIDsStorage({
+ type: 'set',
+ threadIDs: currentUnreadThickThreadIDs,
+ forceWrite: true,
+ });
+ return currentUnreadThickThreadIDs;
+ }
+ return getNotifsUnreadThickThreadIDs();
+ })();
+
+ [queriedUnreadCounts, unreadThickThreadIDs] = await Promise.all([
queryNotifsUnreadCountStorage(unreadCountQueries),
+ handleUnreadThickThreadIDsInNotifsStoragePromise,
updateNotifsUnreadCountStorage(unreadCountUpdates),
]);
@@ -51,10 +75,21 @@
totalUnreadCount += queriedUnreadCounts[keyserverID];
}
+ totalUnreadCount += unreadThickThreadIDs.length;
document.title = getTitle(totalUnreadCount);
electron?.setBadge(totalUnreadCount === 0 ? null : totalUnreadCount);
})();
- }, [unreadCount, connection]);
+ }, [
+ tunnelbrokerSocketState,
+ currentUnreadThickThreadIDs,
+ unreadCount,
+ connection,
+ ]);
+}
+
+function BadgeHandler(): React.Node {
+ useBadgeHandler();
+ return null;
}
-export default useBadgeHandler;
+export default BadgeHandler;
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
@@ -88,6 +88,12 @@
const INDEXED_DB_NOTIFS_ACCOUNT_ENCRYPTION_KEY_DB_LABEL =
'notificationAccountEncryptionKey';
+// thick threads unread count
+const INDEXED_DB_UNREAD_THICK_THREAD_IDS = 'unreadThickThreadIDs';
+const INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL =
+ 'unreadThickThreadIDsEncryptionKey';
+const INDEXED_DB_UNREAD_THICK_THREADS_SYNC_KEY = 'unreadThickThreadIDsSyncKey';
+
async function deserializeEncryptedData<T>(
encryptedData: EncryptedData,
encryptionKey: CryptoKey,
@@ -456,16 +462,25 @@
updatedOlmData = resultUpdatedOlmData;
updatedNotifsAccount = resultUpdatedNotifsAccount;
- await persistNotifsAccountWithOlmData({
- accountWithPicklingKey: updatedNotifsAccount,
- accountEncryptionKey,
- encryptionKey,
- olmData: updatedOlmData,
- olmDataKey,
- olmEncryptionKeyDBLabel,
- synchronizationValue,
- forceWrite: false,
- });
+ const { threadID } = decryptedNotification;
+
+ await Promise.all([
+ persistNotifsAccountWithOlmData({
+ accountWithPicklingKey: updatedNotifsAccount,
+ accountEncryptionKey,
+ encryptionKey,
+ olmData: updatedOlmData,
+ olmDataKey,
+ olmEncryptionKeyDBLabel,
+ synchronizationValue,
+ forceWrite: false,
+ }),
+ updateNotifsUnreadThickThreadIDsStorage({
+ type: 'add',
+ threadIDs: [threadID],
+ forceWrite: false,
+ }),
+ ]);
return { id, ...decryptedNotification };
}
@@ -585,16 +600,26 @@
encryptedPayload,
);
- await persistNotifsAccountWithOlmData({
- accountWithPicklingKey: updatedNotifsAccount,
- accountEncryptionKey,
- encryptionKey,
- olmData: updatedOlmData,
- olmDataKey,
- olmEncryptionKeyDBLabel,
- synchronizationValue,
- forceWrite: false,
- });
+ const { threadID } = decryptedNotification;
+ invariant(typeof threadID === 'string', 'threadID should be string');
+
+ await Promise.all([
+ persistNotifsAccountWithOlmData({
+ accountWithPicklingKey: updatedNotifsAccount,
+ accountEncryptionKey,
+ encryptionKey,
+ olmData: updatedOlmData,
+ olmDataKey,
+ olmEncryptionKeyDBLabel,
+ synchronizationValue,
+ forceWrite: false,
+ }),
+ updateNotifsUnreadThickThreadIDsStorage({
+ type: 'add',
+ threadIDs: [threadID],
+ forceWrite: false,
+ }),
+ ]);
return decryptedNotification;
}
@@ -1253,6 +1278,118 @@
return Object.fromEntries(queriedUnreadCounts);
}
+async function updateNotifsUnreadThickThreadIDsStorage(input: {
+ +type: 'add' | 'remove' | 'set',
+ +threadIDs: $ReadOnlyArray<string>,
+ +forceWrite: boolean,
+}): Promise<void> {
+ const { type, threadIDs, forceWrite } = input;
+
+ const {
+ values: {
+ [INDEXED_DB_UNREAD_THICK_THREAD_IDS]: encryptedData,
+ [INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL]:
+ encryptionKey,
+ },
+ synchronizationValue,
+ } = await localforage.getMultipleItems<{
+ unreadThickThreadIDs: ?EncryptedData,
+ unreadThickThreadIDsEncryptionKey: ?(CryptoKey | SubtleCrypto$JsonWebKey),
+ }>(
+ [
+ INDEXED_DB_UNREAD_THICK_THREAD_IDS,
+ INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL,
+ ],
+ INDEXED_DB_UNREAD_THICK_THREADS_SYNC_KEY,
+ );
+
+ let unreadThickThreadIDs;
+ let unreadThickThreadIDsEncryptionKey;
+
+ if (encryptedData && encryptionKey) {
+ unreadThickThreadIDsEncryptionKey = await validateCryptoKey(encryptionKey);
+ unreadThickThreadIDs = new Set(
+ await deserializeEncryptedData<Array<string>>(
+ encryptedData,
+ unreadThickThreadIDsEncryptionKey,
+ ),
+ );
+ } else {
+ unreadThickThreadIDs = new Set<string>();
+ unreadThickThreadIDsEncryptionKey = await generateCryptoKey({
+ extractable: isDesktopSafari,
+ });
+ }
+
+ if (type === 'add') {
+ for (const threadID of threadIDs) {
+ unreadThickThreadIDs.add(threadID);
+ }
+ } else if (type === 'remove') {
+ for (const threadID of threadIDs) {
+ unreadThickThreadIDs.delete(threadID);
+ }
+ } else {
+ unreadThickThreadIDs = new Set(threadIDs);
+ }
+
+ const [encryptionKeyPersistentForm, updatedEncryptedData] = await Promise.all(
+ [
+ getCryptoKeyPersistentForm(unreadThickThreadIDsEncryptionKey),
+ serializeUnencryptedData(
+ [...unreadThickThreadIDs],
+ unreadThickThreadIDsEncryptionKey,
+ ),
+ ],
+ );
+
+ const newSynchronizationValue = uuid.v4();
+ await localforage.setMultipleItems(
+ {
+ [INDEXED_DB_UNREAD_THICK_THREAD_IDS]: updatedEncryptedData,
+ [INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL]:
+ encryptionKeyPersistentForm,
+ },
+ INDEXED_DB_UNREAD_THICK_THREADS_SYNC_KEY,
+ synchronizationValue,
+ newSynchronizationValue,
+ forceWrite,
+ );
+}
+
+async function getNotifsUnreadThickThreadIDs(): Promise<
+ $ReadOnlyArray<string>,
+> {
+ const {
+ values: {
+ [INDEXED_DB_UNREAD_THICK_THREAD_IDS]: encryptedData,
+ [INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL]:
+ encryptionKey,
+ },
+ } = await localforage.getMultipleItems<{
+ unreadThickThreadIDs: ?EncryptedData,
+ unreadThickThreadIDsEncryptionKey: ?(CryptoKey | SubtleCrypto$JsonWebKey),
+ }>(
+ [
+ INDEXED_DB_UNREAD_THICK_THREAD_IDS,
+ INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL,
+ ],
+ INDEXED_DB_UNREAD_THICK_THREADS_SYNC_KEY,
+ );
+
+ if (!encryptionKey || !encryptedData) {
+ return [];
+ }
+
+ const unreadThickThreadIDsEncryptionKey =
+ await validateCryptoKey(encryptionKey);
+
+ return await deserializeEncryptedData<Array<string>>(
+ encryptedData,
+ unreadThickThreadIDsEncryptionKey,
+ );
+}
+
export {
decryptWebNotification,
decryptDesktopNotification,
@@ -1268,4 +1405,6 @@
persistEncryptionKey,
retrieveEncryptionKey,
persistNotifsAccountWithOlmData,
+ updateNotifsUnreadThickThreadIDsStorage,
+ getNotifsUnreadThickThreadIDs,
};

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 19, 7:21 PM (21 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2324191
Default Alt Text
D13210.id43814.diff (11 KB)

Event Timeline