Merge remote-tracking branch 'parent/main' into upstream-20240813

This commit is contained in:
KMY 2024-08-13 07:01:38 +09:00
commit e7ccc0539f
358 changed files with 4653 additions and 4261 deletions

View file

@ -2,26 +2,33 @@ import { FormattedMessage } from 'react-intl';
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import ReplyIcon from '@/material-icons/400-24px/reply-fill.svg?react';
import type { StatusVisibility } from 'mastodon/api_types/statuses';
import { me } from 'mastodon/initial_state';
import type { NotificationGroupMention } from 'mastodon/models/notification_group';
import type { Status } from 'mastodon/models/status';
import { useAppSelector } from 'mastodon/store';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationWithStatus } from './notification_with_status';
const labelRenderer: LabelRenderer = (values) => (
const mentionLabelRenderer: LabelRenderer = () => (
<FormattedMessage id='notification.label.mention' defaultMessage='Mention' />
);
const privateMentionLabelRenderer: LabelRenderer = () => (
<FormattedMessage
id='notification.mention'
defaultMessage='{name} mentioned you'
values={values}
id='notification.label.private_mention'
defaultMessage='Private mention'
/>
);
const privateMentionLabelRenderer: LabelRenderer = (values) => (
const replyLabelRenderer: LabelRenderer = () => (
<FormattedMessage id='notification.label.reply' defaultMessage='Reply' />
);
const privateReplyLabelRenderer: LabelRenderer = () => (
<FormattedMessage
id='notification.private_mention'
defaultMessage='{name} privately mentioned you'
values={values}
id='notification.label.private_reply'
defaultMessage='Private reply'
/>
);
@ -29,27 +36,30 @@ export const NotificationMention: React.FC<{
notification: NotificationGroupMention;
unread: boolean;
}> = ({ notification, unread }) => {
const statusVisibility = useAppSelector(
(state) =>
state.statuses.getIn([
notification.statusId,
'visibility',
]) as StatusVisibility,
);
const [isDirect, isReply] = useAppSelector((state) => {
const status = state.statuses.get(notification.statusId) as Status;
return [
status.get('visibility') === 'direct',
status.get('in_reply_to_account_id') === me,
] as const;
});
let labelRenderer = mentionLabelRenderer;
if (isReply && isDirect) labelRenderer = privateReplyLabelRenderer;
else if (isReply) labelRenderer = replyLabelRenderer;
else if (isDirect) labelRenderer = privateMentionLabelRenderer;
return (
<NotificationWithStatus
type='mention'
icon={statusVisibility === 'direct' ? AlternateEmailIcon : ReplyIcon}
icon={isReply ? ReplyIcon : AlternateEmailIcon}
iconId='reply'
accountIds={notification.sampleAccountIds}
count={notification.notifications_count}
statusId={notification.statusId}
labelRenderer={
statusVisibility === 'direct'
? privateMentionLabelRenderer
: labelRenderer
}
labelRenderer={labelRenderer}
unread={unread}
/>
);

View file

@ -4,8 +4,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { Helmet } from 'react-helmet';
import { createSelector } from '@reduxjs/toolkit';
import { useDebouncedCallback } from 'use-debounce';
import DoneAllIcon from '@/material-icons/400-24px/done_all.svg?react';
@ -26,16 +24,14 @@ import type { NotificationGap } from 'mastodon/reducers/notification_groups';
import {
selectUnreadNotificationGroupsCount,
selectPendingNotificationGroupsCount,
selectAnyPendingNotification,
selectNotificationGroups,
} from 'mastodon/selectors/notifications';
import {
selectNeedsNotificationPermission,
selectSettingsNotificationsExcludedTypes,
selectSettingsNotificationsQuickFilterActive,
selectSettingsNotificationsQuickFilterShow,
selectSettingsNotificationsShowUnread,
} from 'mastodon/selectors/settings';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import type { RootState } from 'mastodon/store';
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
import { submitMarkers } from '../../actions/markers';
@ -61,41 +57,19 @@ const messages = defineMessages({
},
});
const getNotifications = createSelector(
[
selectSettingsNotificationsQuickFilterShow,
selectSettingsNotificationsQuickFilterActive,
selectSettingsNotificationsExcludedTypes,
(state: RootState) => state.notificationGroups.groups,
],
(showFilterBar, allowedType, excludedTypes, notifications) => {
if (!showFilterBar || allowedType === 'all') {
// used if user changed the notification settings after loading the notifications from the server
// otherwise a list of notifications will come pre-filtered from the backend
// we need to turn it off for FilterBar in order not to block ourselves from seeing a specific category
return notifications.filter(
(item) => item.type === 'gap' || !excludedTypes.includes(item.type),
);
}
return notifications.filter(
(item) => item.type === 'gap' || allowedType === item.type,
);
},
);
export const Notifications: React.FC<{
columnId?: string;
multiColumn?: boolean;
}> = ({ columnId, multiColumn }) => {
const intl = useIntl();
const notifications = useAppSelector(getNotifications);
const notifications = useAppSelector(selectNotificationGroups);
const dispatch = useAppDispatch();
const isLoading = useAppSelector((s) => s.notificationGroups.isLoading);
const hasMore = notifications.at(-1)?.type === 'gap';
const lastReadId = useAppSelector((s) =>
selectSettingsNotificationsShowUnread(s)
? s.notificationGroups.lastReadId
? s.notificationGroups.readMarkerId
: '0',
);
@ -105,11 +79,13 @@ export const Notifications: React.FC<{
selectUnreadNotificationGroupsCount,
);
const anyPendingNotification = useAppSelector(selectAnyPendingNotification);
const isUnread = unreadNotificationsCount > 0;
const canMarkAsRead =
useAppSelector(selectSettingsNotificationsShowUnread) &&
unreadNotificationsCount > 0;
anyPendingNotification;
const needsNotificationPermission = useAppSelector(
selectNeedsNotificationPermission,