From c8abb95e8e2a57d4d07ea739ee220dc1b44c4e4b Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Sun, 22 Sep 2024 13:55:37 +0800 Subject: [PATCH] Improve grouping for server-side grouping Migrate from v2_alpha to v2 --- src/components/notification.jsx | 79 +++++++++++++++++--- src/pages/notifications.jsx | 2 +- src/utils/group-notifications.jsx | 117 ++++++++++++++++++++---------- 3 files changed, 150 insertions(+), 48 deletions(-) diff --git a/src/components/notification.jsx b/src/components/notification.jsx index 0e11662e..89ae71b3 100644 --- a/src/components/notification.jsx +++ b/src/components/notification.jsx @@ -3,6 +3,7 @@ import { useLingui } from '@lingui/react'; import { Fragment } from 'preact'; import { memo } from 'preact/compat'; +import { api } from '../utils/api'; import shortenNumber from '../utils/shorten-number'; import states, { statusKey } from '../utils/states'; import { getCurrentAccountID } from '../utils/store-utils'; @@ -302,6 +303,7 @@ function Notification({ disableContextMenu, }) { const { _ } = useLingui(); + const { masto } = api(); const { id, status, @@ -313,9 +315,11 @@ function Notification({ _ids, _accounts, _statuses, + _groupKeys, // Server-side grouped notification sampleAccounts, notificationsCount, + groupKey, } = notification; let { type } = notification; @@ -443,10 +447,15 @@ function Notification({ console.debug('RENDER Notification', notification.id); + const sameCount = + notificationsCount > 0 && notificationsCount <= sampleAccounts?.length; + const expandAccounts = sameCount ? 'local' : 'remote'; + return (
{' '} ))} - + {type === 'favourite+reblog' && expandAccounts === 'remote' ? ( + + ) : ( + + )}

)} {!_accounts?.length && sampleAccounts?.length > 1 && ( diff --git a/src/pages/notifications.jsx b/src/pages/notifications.jsx index 06fbb5db..36caf316 100644 --- a/src/pages/notifications.jsx +++ b/src/pages/notifications.jsx @@ -69,7 +69,7 @@ export function mastoFetchNotifications(opts = {}) { memSupportsGroupedNotifications() ) { // https://github.com/mastodon/mastodon/pull/29889 - return masto.v2_alpha.notifications.list({ + return masto.v2.notifications.list({ limit: NOTIFICATIONS_GROUPED_LIMIT, ...opts, }); diff --git a/src/utils/group-notifications.jsx b/src/utils/group-notifications.jsx index 1aeb0faf..0d307ead 100644 --- a/src/utils/group-notifications.jsx +++ b/src/utils/group-notifications.jsx @@ -68,66 +68,105 @@ export function groupNotifications2(groupNotifications) { }; }); - // DISABLED FOR NOW. // Merge favourited and reblogged of same status into a single notification // - new type: "favourite+reblog" // - sum numbers for `notificationsCount` and `sampleAccounts` - // const mappedNotifications = {}; - // const newNewGroupNotifications = []; - // for (let i = 0; i < newGroupNotifications.length; i++) { - // const gn = newGroupNotifications[i]; - // const { type, status, createdAt, notificationsCount, sampleAccounts } = gn; - // const date = createdAt ? new Date(createdAt).toLocaleDateString() : ''; - // let virtualType = type; - // if (type === 'favourite' || type === 'reblog') { - // virtualType = 'favourite+reblog'; - // } - // const key = `${status?.id}-${virtualType}-${date}`; - // const mappedNotification = mappedNotifications[key]; - // if (mappedNotification) { - // const accountIDs = mappedNotification.sampleAccounts.map((a) => a.id); - // sampleAccounts.forEach((a) => { - // if (!accountIDs.includes(a.id)) { - // mappedNotification.sampleAccounts.push(a); - // } - // }); - // mappedNotification.notificationsCount = Math.max( - // mappedNotification.notificationsCount, - // notificationsCount, - // mappedNotification.sampleAccounts.length, - // ); - // } else { - // mappedNotifications[key] = { - // ...gn, - // type: virtualType, - // }; - // newNewGroupNotifications.push(mappedNotifications[key]); - // } - // } + const notificationsMap = {}; + const newGroupNotifications1 = []; + for (let i = 0; i < newGroupNotifications.length; i++) { + const gn = newGroupNotifications[i]; + const { + type, + status, + createdAt, + notificationsCount, + sampleAccounts, + groupKey, + } = gn; + const date = createdAt ? new Date(createdAt).toLocaleDateString() : ''; + let virtualType = type; + const sameCount = + notificationsCount > 0 && notificationsCount === sampleAccounts?.length; + // if (sameCount && (type === 'favourite' || type === 'reblog')) { + if (type === 'favourite' || type === 'reblog') { + virtualType = 'favourite+reblog'; + } + // const key = `${status?.id}-${virtualType}-${date}-${sameCount ? 1 : 0}`; + const key = `${status?.id}-${virtualType}-${date}`; + const mappedNotification = notificationsMap[key]; + if (mappedNotification) { + // Merge sampleAccounts + merge _types + sampleAccounts.forEach((a) => { + const mappedAccount = mappedNotification.sampleAccounts.find( + (ma) => ma.id === a.id, + ); + if (!mappedAccount) { + mappedNotification.sampleAccounts.push({ + ...a, + _types: [type], + }); + } else { + mappedAccount._types.push(type); + mappedAccount._types.sort().reverse(); + } + }); + // mappedNotification.notificationsCount = + // mappedNotification.sampleAccounts.length; + mappedNotification.notificationsCount = Math.min( + mappedNotification.notificationsCount, + notificationsCount, + ); + mappedNotification._notificationsCount.push(notificationsCount); + mappedNotification._accounts = mappedNotification.sampleAccounts; + mappedNotification._groupKeys.push(groupKey); + } else { + const accounts = sampleAccounts.map((a) => ({ + ...a, + _types: [type], + })); + notificationsMap[key] = { + ...gn, + sampleAccounts: accounts, + type: virtualType, + _accounts: accounts, + _groupKeys: groupKey ? [groupKey] : [], + _notificationsCount: [notificationsCount], + }; + newGroupNotifications1.push(notificationsMap[key]); + } + } // 2nd pass. // - Group 1 account favourte/reblog multiple posts - // - _statuses: [status, status, ...] + // - _statuses: [status, status, ...] const notificationsMap2 = {}; const newGroupNotifications2 = []; - for (let i = 0; i < newGroupNotifications.length; i++) { - const gn = newGroupNotifications[i]; - const { type, account, _accounts, sampleAccounts, createdAt } = gn; + for (let i = 0; i < newGroupNotifications1.length; i++) { + const gn = newGroupNotifications1[i]; + const { type, account, _accounts, sampleAccounts, createdAt, groupKey } = + gn; const date = createdAt ? new Date(createdAt).toLocaleDateString() : ''; const hasOneAccount = sampleAccounts?.length === 1 || _accounts?.length === 1; - if ((type === 'favourite' || type === 'reblog') && hasOneAccount) { + if ( + (type === 'favourite' || + type === 'reblog' || + type === 'favourite+reblog') && + hasOneAccount + ) { const key = `${account?.id}-${type}-${date}`; const mappedNotification = notificationsMap2[key]; if (mappedNotification) { mappedNotification._statuses.push(gn.status); mappedNotification._ids += `-${gn.id}`; + mappedNotification._groupKeys.push(groupKey); } else { let n = (notificationsMap2[key] = { ...gn, type, _ids: gn.id, _statuses: [gn.status], + _groupKeys: groupKey ? [groupKey] : [], }); newGroupNotifications2.push(n); } @@ -136,6 +175,8 @@ export function groupNotifications2(groupNotifications) { } } + console.log('newGroupNotifications2', newGroupNotifications2); + return newGroupNotifications2; }