Skip to content

Commit

Permalink
Merge remote-tracking branch 'parent/main' into upstream-20240822
Browse files Browse the repository at this point in the history
  • Loading branch information
kmycode committed Aug 22, 2024
2 parents 36142df + 2da687a commit 55f1176
Show file tree
Hide file tree
Showing 34 changed files with 401 additions and 601 deletions.
2 changes: 2 additions & 0 deletions app/helpers/kmyblue_capabilities_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

module KmyblueCapabilitiesHelper
KMYBLUE_API_VERSION = 1

def fedibird_capabilities
capabilities = %i(
enable_wide_emoji
Expand Down
4 changes: 2 additions & 2 deletions app/javascript/mastodon/actions/interactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -746,12 +746,12 @@ export function expandMentionedUsersFail(id, error) {
};
}

function toggleReblogWithoutConfirmation(status, privacy) {
function toggleReblogWithoutConfirmation(status, visibility) {
return (dispatch) => {
if (status.get('reblogged')) {
dispatch(unreblog({ statusId: status.get('id') }));
} else {
dispatch(reblog({ statusId: status.get('id'), privacy }));
dispatch(reblog({ statusId: status.get('id'), visibility }));
}
};
}
Expand Down
23 changes: 23 additions & 0 deletions app/javascript/mastodon/actions/notification_groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
} from 'mastodon/api_types/notifications';
import { allNotificationTypes } from 'mastodon/api_types/notifications';
import type { ApiStatusJSON } from 'mastodon/api_types/statuses';
import { usePendingItems } from 'mastodon/initial_state';
import type { NotificationGap } from 'mastodon/reducers/notification_groups';
import {
selectSettingsNotificationsExcludedTypes,
Expand Down Expand Up @@ -103,6 +104,28 @@ export const fetchNotificationsGap = createDataLoadingThunk(
},
);

export const pollRecentNotifications = createDataLoadingThunk(
'notificationGroups/pollRecentNotifications',
async (_params, { getState }) => {
return apiFetchNotifications({
max_id: undefined,
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
since_id: usePendingItems
? getState().notificationGroups.groups.find(
(group) => group.type !== 'gap',
)?.page_max_id
: undefined,
});
},
({ notifications, accounts, statuses }, { dispatch }) => {
dispatch(importFetchedAccounts(accounts));
dispatch(importFetchedStatuses(statuses));
dispatchAssociatedRecords(dispatch, notifications);

return { notifications };
},
);

export const processNewNotificationForGroups = createAppAsyncThunk(
'notificationGroups/processNew',
(notification: ApiNotificationJSON, { dispatch, getState }) => {
Expand Down
25 changes: 19 additions & 6 deletions app/javascript/mastodon/actions/streaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
deleteAnnouncement,
} from './announcements';
import { updateConversations } from './conversations';
import { processNewNotificationForGroups, refreshStaleNotificationGroups } from './notification_groups';
import { processNewNotificationForGroups, refreshStaleNotificationGroups, pollRecentNotifications as pollRecentGroupNotifications } from './notification_groups';
import { updateNotifications, expandNotifications, updateEmojiReactions } from './notifications';
import { updateStatus } from './statuses';
import {
Expand Down Expand Up @@ -38,7 +38,7 @@ const randomUpTo = max =>
* @param {string} channelName
* @param {Object.<string, string>} params
* @param {Object} options
* @param {function(Function): Promise<void>} [options.fallback]
* @param {function(Function, Function): Promise<void>} [options.fallback]
* @param {function(): void} [options.fillGaps]
* @param {function(object): boolean} [options.accept]
* @returns {function(): void}
Expand All @@ -53,11 +53,11 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
let pollingId;

/**
* @param {function(Function): Promise<void>} fallback
* @param {function(Function, Function): Promise<void>} fallback
*/

const useFallback = async fallback => {
await fallback(dispatch);
await fallback(dispatch, getState);
// eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
pollingId = setTimeout(() => useFallback(fallback), 20000 + randomUpTo(20000));
};
Expand Down Expand Up @@ -144,10 +144,23 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti

/**
* @param {Function} dispatch
* @param {Function} getState
*/
async function refreshHomeTimelineAndNotification(dispatch) {
async function refreshHomeTimelineAndNotification(dispatch, getState) {
await dispatch(expandHomeTimeline({ maxId: undefined }));
await dispatch(expandNotifications({}));

// TODO: remove this once the groups feature replaces the previous one
if(getState().settings.getIn(['notifications', 'groupingBeta'], false)) {
// TODO: polling for merged notifications
try {
await dispatch(pollRecentGroupNotifications());
} catch (error) {
// TODO
}
} else {
await dispatch(expandNotifications({}));
}

await dispatch(fetchAnnouncements());
}

Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/api/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const exceptInvalidNotifications = (
export const apiFetchNotifications = async (params?: {
exclude_types?: string[];
max_id?: string;
since_id?: string;
}) => {
const response = await api().request<ApiNotificationGroupsResultJSON>({
method: 'GET',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Link } from 'react-router-dom';

import { useAppSelector } from 'mastodon/store';

export const DisplayedName: React.FC<{
accountIds: string[];
}> = ({ accountIds }) => {
const lastAccountId = accountIds[0] ?? '0';
const account = useAppSelector((state) => state.accounts.get(lastAccountId));

if (!account) return null;

return (
<Link
to={`/@${account.acct}`}
title={`@${account.acct}`}
data-hover-card-account={account.id}
>
<bdi dangerouslySetInnerHTML={{ __html: account.display_name_html }} />
</Link>
);
};

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,27 @@ import type { NotificationGroupAdminSignUp } from 'mastodon/models/notification_
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';

const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.admin.sign_up'
defaultMessage='{name} signed up'
values={values}
/>
);
const labelRenderer: LabelRenderer = (displayedName, total) => {
if (total === 1)
return (
<FormattedMessage
id='notification.admin.sign_up'
defaultMessage='{name} signed up'
values={{ name: displayedName }}
/>
);

return (
<FormattedMessage
id='notification.admin.sign_up.name_and_others'
defaultMessage='{name} and {count, plural, one {# other} other {# others}} signed up'
values={{
name: displayedName,
count: total - 1,
}}
/>
);
};

export const NotificationAdminSignUp: React.FC<{
notification: NotificationGroupAdminSignUp;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
import { FormattedMessage } from 'react-intl';

import { Link } from 'react-router-dom';

import EmojiReactionIcon from '@/material-icons/400-24px/mood.svg?react';
import type { NotificationGroupEmojiReaction } from 'mastodon/models/notification_group';
import { useAppSelector } from 'mastodon/store';

import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';

const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.emoji_reaction'
defaultMessage='{name} reacted your status with emoji'
values={values}
/>
);
const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
if (total === 1)
return (
<FormattedMessage
id='notification.emoji_reaction'
defaultMessage='{name} reacted your status with emoji'
values={{ name: displayedName }}
/>
);

return (
<FormattedMessage
id='notification.emoji_reaction.name_and_others_with_link'
defaultMessage='{name} and <a>{count, plural, one {# other} other {# others}}</a> reacted your post with emoji'
values={{
name: displayedName,
count: total - 1,
a: (chunks) =>
seeMoreHref ? <Link to={seeMoreHref}>{chunks}</Link> : chunks,
}}
/>
);
};

export const NotificationEmojiReaction: React.FC<{
notification: NotificationGroupEmojiReaction;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
import { FormattedMessage } from 'react-intl';

import { Link } from 'react-router-dom';

import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
import type { NotificationGroupFavourite } from 'mastodon/models/notification_group';
import { useAppSelector } from 'mastodon/store';

import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';

const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.favourite'
defaultMessage='{name} favorited your status'
values={values}
/>
);
const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
if (total === 1)
return (
<FormattedMessage
id='notification.favourite'
defaultMessage='{name} favorited your status'
values={{ name: displayedName }}
/>
);

return (
<FormattedMessage
id='notification.favourite.name_and_others_with_link'
defaultMessage='{name} and <a>{count, plural, one {# other} other {# others}}</a> favorited your post'
values={{
name: displayedName,
count: total - 1,
a: (chunks) =>
seeMoreHref ? <Link to={seeMoreHref}>{chunks}</Link> : chunks,
}}
/>
);
};

export const NotificationFavourite: React.FC<{
notification: NotificationGroupFavourite;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,27 @@ import { useAppSelector } from 'mastodon/store';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';

const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.follow'
defaultMessage='{name} followed you'
values={values}
/>
);
const labelRenderer: LabelRenderer = (displayedName, total) => {
if (total === 1)
return (
<FormattedMessage
id='notification.follow'
defaultMessage='{name} followed you'
values={{ name: displayedName }}
/>
);

return (
<FormattedMessage
id='notification.follow.name_and_others'
defaultMessage='{name} and {count, plural, one {# other} other {# others}} followed you'
values={{
name: displayedName,
count: total - 1,
}}
/>
);
};

const FollowerCount: React.FC<{ accountId: string }> = ({ accountId }) => {
const account = useAppSelector((s) => s.accounts.get(accountId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,27 @@ const messages = defineMessages({
reject: { id: 'follow_request.reject', defaultMessage: 'Reject' },
});

const labelRenderer: LabelRenderer = (values) => (
<FormattedMessage
id='notification.follow_request'
defaultMessage='{name} has requested to follow you'
values={values}
/>
);
const labelRenderer: LabelRenderer = (displayedName, total) => {
if (total === 1)
return (
<FormattedMessage
id='notification.follow_request'
defaultMessage='{name} has requested to follow you'
values={{ name: displayedName }}
/>
);

return (
<FormattedMessage
id='notification.follow_request.name_and_others'
defaultMessage='{name} and {count, plural, one {# other} other {# others}} has requested to follow you'
values={{
name: displayedName,
count: total - 1,
}}
/>
);
};

export const NotificationFollowRequest: React.FC<{
notification: NotificationGroupFollowRequest;
Expand Down
Loading

0 comments on commit 55f1176

Please sign in to comment.