Group notifications/reposts fetched from the same page

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak
2023-12-30 22:19:32 +01:00
parent 167b293e9b
commit c2959f2137
11 changed files with 183 additions and 61 deletions

View File

@ -141,47 +141,50 @@ const isBroken = (status: APIEntity) => {
}
};
const importFetchedStatuses = (statuses: APIEntity[]) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const accounts: APIEntity[] = [];
const normalStatuses: APIEntity[] = [];
const polls: APIEntity[] = [];
const importFetchedStatuses = (statuses: APIEntity[]) => (dispatch: AppDispatch) => {
const accounts: APIEntity[] = [];
const normalStatuses: APIEntity[] = [];
const polls: APIEntity[] = [];
function processStatus(status: APIEntity) {
// Skip broken statuses
if (isBroken(status)) return;
function processStatus(status: APIEntity) {
// Skip broken statuses
if (isBroken(status)) return;
normalStatuses.push(status);
accounts.push(status.account);
normalStatuses.push(status);
if (status.reblog?.id) {
processStatus(status.reblog);
}
// Fedibird quotes
if (status.quote?.id) {
processStatus(status.quote);
}
if (status.pleroma?.quote?.id) {
processStatus(status.pleroma.quote);
}
if (status.poll?.id) {
polls.push(status.poll);
}
if (status.group?.id) {
dispatch(importFetchedGroup(status.group));
}
accounts.push(status.account);
if (status.accounts) {
accounts.push(...status.accounts);
}
statuses.forEach(processStatus);
if (status.reblog?.id) {
processStatus(status.reblog);
}
dispatch(importPolls(polls));
dispatch(importFetchedAccounts(accounts));
dispatch(importStatuses(normalStatuses));
};
// Fedibird quotes
if (status.quote?.id) {
processStatus(status.quote);
}
if (status.pleroma?.quote?.id) {
processStatus(status.pleroma.quote);
}
if (status.poll?.id) {
polls.push(status.poll);
}
if (status.group?.id) {
dispatch(importFetchedGroup(status.group));
}
}
statuses.forEach(processStatus);
dispatch(importPolls(polls));
dispatch(importFetchedAccounts(accounts));
dispatch(importStatuses(normalStatuses));
};
const importFetchedPoll = (poll: APIEntity) =>
(dispatch: AppDispatch) => {

View File

@ -60,7 +60,6 @@ type FilterType = keyof typeof FILTER_TYPES;
defineMessages({
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
group: { id: 'notifications.group', defaultMessage: '{count, plural, one {# notification} other {# notifications}}' },
});
const fetchRelatedRelationships = (dispatch: AppDispatch, notifications: APIEntity[]) => {
@ -188,6 +187,42 @@ const noOp = () => new Promise(f => f(undefined));
let abortExpandNotifications = new AbortController();
const STATUS_NOTIFICATION_TYPES = [
'favourite',
'reblog',
// WIP separate notifications for each reaction?
// 'pleroma:emoji_reaction',
'pleroma:event_reminder',
'pleroma:participation_accepted',
'pleroma:participation_request',
];
const deduplicateNotifications = (notifications: any[]) => {
const deduplicatedNotifications: any[] = [];
for (const notification of notifications) {
if (STATUS_NOTIFICATION_TYPES.includes(notification.type)) {
const existingNotification = deduplicatedNotifications
.find(deduplicatedNotification => deduplicatedNotification.type === notification.type && deduplicatedNotification.status?.id === notification.status?.id);
if (existingNotification) {
if (existingNotification?.accounts) {
existingNotification.accounts.push(notification.account);
} else {
existingNotification.accounts = [existingNotification.account, notification.account];
}
existingNotification.id += '+' + notification.id;
} else {
deduplicatedNotifications.push(notification);
}
} else {
deduplicatedNotifications.push(notification);
}
}
return deduplicatedNotifications;
};
const expandNotifications = ({ maxId }: Record<string, any> = {}, done: () => any = noOp, abort?: boolean) =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return dispatch(noOp);
@ -259,7 +294,9 @@ const expandNotifications = ({ maxId }: Record<string, any> = {}, done: () => an
const statusesFromGroups = (Object.values(entries.statuses) as Status[]).filter((status) => !!status.group);
dispatch(fetchGroupRelationships(statusesFromGroups.map((status: any) => status.group?.id)));
dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore));
const deduplicatedNotifications = deduplicateNotifications(response.data);
dispatch(expandNotificationsSuccess(deduplicatedNotifications, next ? next.uri : null, isLoadingMore));
fetchRelatedRelationships(dispatch, response.data);
done();
}).catch(error => {

View File

@ -146,6 +146,27 @@ const parseTags = (tags: Record<string, any[]> = {}, mode: 'any' | 'all' | 'none
});
};
const deduplicateStatuses = (statuses: any[]) => {
const deduplicatedStatuses: any[] = [];
for (const status of statuses) {
const reblogged = status.reblog && deduplicatedStatuses.find((deduplicatedStatuses) => deduplicatedStatuses.reblog?.id === status.reblog.id);
if (reblogged) {
if (reblogged.accounts) {
reblogged.accounts.push(status.account);
} else {
reblogged.accounts = [reblogged.account, status.account];
}
reblogged.id += ':' + status.id;
} else {
deduplicatedStatuses.push(status);
}
}
return deduplicatedStatuses;
};
const expandTimeline = (timelineId: string, path: string, params: Record<string, any> = {}, done = noOp) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const timeline = getState().timelines.get(timelineId) || {} as Record<string, any>;
@ -172,12 +193,15 @@ const expandTimeline = (timelineId: string, path: string, params: Record<string,
return api(getState).get(path, { params }).then(response => {
dispatch(importFetchedStatuses(response.data));
const statuses = deduplicateStatuses(response.data);
dispatch(importFetchedStatuses(statuses.filter(status => status.accounts)));
const statusesFromGroups = (response.data as Status[]).filter((status) => !!status.group);
dispatch(fetchGroupRelationships(statusesFromGroups.map((status: any) => status.group?.id)));
dispatch(expandTimelineSuccess(
timelineId,
response.data,
statuses,
getNextLink(response),
getPrevLink(response),
response.status === 206,