diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 61dcb87c23..aef51a6479 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -30,9 +30,8 @@ class Api::V1::AccountsController < Api::BaseController
end
def follow
- FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs), with_rate_limit: true)
-
- options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } }
+ follow = FollowService.new.call(current_user.account, @account, reblogs: params.key?(:reblogs) ? truthy_param?(:reblogs) : nil, notify: params.key?(:notify) ? truthy_param?(:notify) : nil, with_rate_limit: true)
+ options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: follow.show_reblogs?, notify: follow.notify? } }, requested_map: { @account.id => false } }
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options)
end
diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb
index 0420b7bef9..b34c76f29e 100644
--- a/app/controllers/api/v1/follow_requests_controller.rb
+++ b/app/controllers/api/v1/follow_requests_controller.rb
@@ -13,7 +13,7 @@ class Api::V1::FollowRequestsController < Api::BaseController
def authorize
AuthorizeFollowService.new.call(account, current_account)
- NotifyService.new.call(current_account, Follow.find_by(account: account, target_account: current_account))
+ NotifyService.new.call(current_account, :follow, Follow.find_by(account: account, target_account: current_account))
render json: account, serializer: REST::RelationshipSerializer, relationships: relationships
end
diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js
index d28f7dad88..723c04e554 100644
--- a/app/javascript/mastodon/actions/accounts.js
+++ b/app/javascript/mastodon/actions/accounts.js
@@ -109,14 +109,14 @@ export function fetchAccountFail(id, error) {
};
};
-export function followAccount(id, reblogs = true) {
+export function followAccount(id, options = { reblogs: true }) {
return (dispatch, getState) => {
const alreadyFollowing = getState().getIn(['relationships', id, 'following']);
const locked = getState().getIn(['accounts', id, 'locked'], false);
dispatch(followAccountRequest(id, locked));
- api(getState).post(`/api/v1/accounts/${id}/follow`, { reblogs }).then(response => {
+ api(getState).post(`/api/v1/accounts/${id}/follow`, options).then(response => {
dispatch(followAccountSuccess(response.data, alreadyFollowing));
}).catch(error => {
dispatch(followAccountFail(error, locked));
diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js
index a26844f848..099e42f6c5 100644
--- a/app/javascript/mastodon/actions/notifications.js
+++ b/app/javascript/mastodon/actions/notifications.js
@@ -59,7 +59,7 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
let filtered = false;
- if (notification.type === 'mention') {
+ if (['mention', 'status'].includes(notification.type)) {
const dropRegex = filters[0];
const regex = filters[1];
const searchIndex = searchTextFromRawStatus(notification.status);
diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js
index 02217b62c5..2b97af4e67 100644
--- a/app/javascript/mastodon/features/account/components/header.js
+++ b/app/javascript/mastodon/features/account/components/header.js
@@ -7,6 +7,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { autoPlayGif, me, isStaff } from 'mastodon/initial_state';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
+import IconButton from 'mastodon/components/icon_button';
import Avatar from 'mastodon/components/avatar';
import { counterRenderer } from 'mastodon/components/common_counter';
import ShortNumber from 'mastodon/components/short_number';
@@ -35,6 +36,8 @@ const messages = defineMessages({
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' },
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
+ enableNotifications: { id: 'account.enable_notifications', defaultMessage: 'Notify me when @{name} posts' },
+ disableNotifications: { id: 'account.disable_notifications', defaultMessage: 'Stop notifying me when @{name} posts' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
@@ -68,8 +71,9 @@ class Header extends ImmutablePureComponent {
onBlock: PropTypes.func.isRequired,
onMention: PropTypes.func.isRequired,
onDirect: PropTypes.func.isRequired,
- onReport: PropTypes.func.isRequired,
onReblogToggle: PropTypes.func.isRequired,
+ onNotifyToggle: PropTypes.func.isRequired,
+ onReport: PropTypes.func.isRequired,
onMute: PropTypes.func.isRequired,
onBlockDomain: PropTypes.func.isRequired,
onUnblockDomain: PropTypes.func.isRequired,
@@ -144,6 +148,7 @@ class Header extends ImmutablePureComponent {
let info = [];
let actionBtn = '';
+ let bellBtn = '';
let lockedIcon = '';
let menu = [];
@@ -173,6 +178,10 @@ class Header extends ImmutablePureComponent {
actionBtn = ;
}
+ if (account.getIn(['relationship', 'requested']) || account.getIn(['relationship', 'following'])) {
+ bellBtn = ;
+ }
+
if (account.get('moved') && !account.getIn(['relationship', 'following'])) {
actionBtn = '';
}
@@ -287,6 +296,7 @@ class Header extends ImmutablePureComponent {
{!suspended && (
{actionBtn}
+ {bellBtn}
diff --git a/app/javascript/mastodon/features/account_timeline/components/header.js b/app/javascript/mastodon/features/account_timeline/components/header.js
index abb15edcc7..6b52defe4a 100644
--- a/app/javascript/mastodon/features/account_timeline/components/header.js
+++ b/app/javascript/mastodon/features/account_timeline/components/header.js
@@ -55,6 +55,10 @@ export default class Header extends ImmutablePureComponent {
this.props.onReblogToggle(this.props.account);
}
+ handleNotifyToggle = () => {
+ this.props.onNotifyToggle(this.props.account);
+ }
+
handleMute = () => {
this.props.onMute(this.props.account);
}
@@ -106,6 +110,7 @@ export default class Header extends ImmutablePureComponent {
onMention={this.handleMention}
onDirect={this.handleDirect}
onReblogToggle={this.handleReblogToggle}
+ onNotifyToggle={this.handleNotifyToggle}
onReport={this.handleReport}
onMute={this.handleMute}
onBlockDomain={this.handleBlockDomain}
diff --git a/app/javascript/mastodon/features/account_timeline/containers/header_container.js b/app/javascript/mastodon/features/account_timeline/containers/header_container.js
index 8728b48068..e12019547e 100644
--- a/app/javascript/mastodon/features/account_timeline/containers/header_container.js
+++ b/app/javascript/mastodon/features/account_timeline/containers/header_container.js
@@ -76,9 +76,9 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
onReblogToggle (account) {
if (account.getIn(['relationship', 'showing_reblogs'])) {
- dispatch(followAccount(account.get('id'), false));
+ dispatch(followAccount(account.get('id'), { reblogs: false }));
} else {
- dispatch(followAccount(account.get('id'), true));
+ dispatch(followAccount(account.get('id'), { reblogs: true }));
}
},
@@ -90,6 +90,14 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
}
},
+ onNotifyToggle (account) {
+ if (account.getIn(['relationship', 'notifying'])) {
+ dispatch(followAccount(account.get('id'), { notify: false }));
+ } else {
+ dispatch(followAccount(account.get('id'), { notify: true }));
+ }
+ },
+
onReport (account) {
dispatch(initReport(account));
},
diff --git a/app/javascript/mastodon/features/notifications/components/filter_bar.js b/app/javascript/mastodon/features/notifications/components/filter_bar.js
index 2fd28d8326..368eb0b7e6 100644
--- a/app/javascript/mastodon/features/notifications/components/filter_bar.js
+++ b/app/javascript/mastodon/features/notifications/components/filter_bar.js
@@ -9,6 +9,7 @@ const tooltips = defineMessages({
boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' },
polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' },
follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },
+ statuses: { id: 'notifications.filter.statuses', defaultMessage: 'Updates from people you follow' },
});
export default @injectIntl
@@ -87,6 +88,13 @@ class FilterBar extends React.PureComponent {
>
+