mirror of
https://github.com/cheeaun/phanpy.git
synced 2024-11-21 16:55:25 +03:00
Improve grouping for server-side grouping
Migrate from v2_alpha to v2
This commit is contained in:
parent
4cc6a6a12c
commit
c8abb95e8e
3 changed files with 150 additions and 48 deletions
|
@ -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 (
|
||||
<div
|
||||
class={`notification notification-${type}`}
|
||||
data-notification-id={_ids || id}
|
||||
data-group-key={_groupKeys?.join(' ') || groupKey}
|
||||
tabIndex="0"
|
||||
>
|
||||
<div
|
||||
|
@ -550,15 +559,67 @@ function Notification({
|
|||
</a>{' '}
|
||||
</Fragment>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
class="small plain"
|
||||
onClick={handleOpenGenericAccounts}
|
||||
>
|
||||
{_accounts.length > AVATARS_LIMIT &&
|
||||
`+${_accounts.length - AVATARS_LIMIT}`}
|
||||
<Icon icon="chevron-down" />
|
||||
</button>
|
||||
{type === 'favourite+reblog' && expandAccounts === 'remote' ? (
|
||||
<button
|
||||
type="button"
|
||||
class="small plain"
|
||||
data-group-keys={_groupKeys.join(' ')}
|
||||
onClick={() => {
|
||||
states.showGenericAccounts = {
|
||||
heading: genericAccountsHeading,
|
||||
fetchAccounts: async () => {
|
||||
const keyAccounts = await Promise.allSettled(
|
||||
_groupKeys.map(async (gKey) => {
|
||||
const iterator = masto.v2.notifications
|
||||
.$select(gKey)
|
||||
.accounts.list();
|
||||
return [gKey, (await iterator.next()).value];
|
||||
}),
|
||||
);
|
||||
const accounts = [];
|
||||
for (const keyAccount of keyAccounts) {
|
||||
const [key, _accounts] = keyAccount.value;
|
||||
const type = /^favourite/.test(key)
|
||||
? 'favourite'
|
||||
: /^reblog/.test(key)
|
||||
? 'reblog'
|
||||
: null;
|
||||
if (!type) continue;
|
||||
for (const account of _accounts) {
|
||||
const theAccount = accounts.find(
|
||||
(a) => a.id === account.id,
|
||||
);
|
||||
if (theAccount) {
|
||||
theAccount._types.push(type);
|
||||
} else {
|
||||
account._types = [type];
|
||||
accounts.push(account);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
done: true,
|
||||
value: accounts,
|
||||
};
|
||||
},
|
||||
showReactions: true,
|
||||
postID: statusKey(actualStatusID, instance),
|
||||
};
|
||||
}}
|
||||
>
|
||||
<Icon icon="chevron-down" />
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
class="small plain"
|
||||
onClick={handleOpenGenericAccounts}
|
||||
>
|
||||
{_accounts.length > AVATARS_LIMIT &&
|
||||
`+${_accounts.length - AVATARS_LIMIT}`}
|
||||
<Icon icon="chevron-down" />
|
||||
</button>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{!_accounts?.length && sampleAccounts?.length > 1 && (
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue