[Glitch] Add option to be notified when a followed user posts

Port 974b1b79ce to glitch-soc

Signed-off-by: Thibaut Girka <thib@sitedethib.com>
This commit is contained in:
Eugen Rochko 2020-09-18 17:26:45 +02:00 committed by Thibaut Girka
parent 0a069bffd9
commit 14869ee656
10 changed files with 93 additions and 7 deletions

View file

@ -126,14 +126,14 @@ export function fetchAccountFail(id, error) {
}; };
}; };
export function followAccount(id, reblogs = true) { export function followAccount(id, options = { reblogs: true }) {
return (dispatch, getState) => { return (dispatch, getState) => {
const alreadyFollowing = getState().getIn(['relationships', id, 'following']); const alreadyFollowing = getState().getIn(['relationships', id, 'following']);
const locked = getState().getIn(['accounts', id, 'locked'], false); const locked = getState().getIn(['accounts', id, 'locked'], false);
dispatch(followAccountRequest(id, locked)); 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)); dispatch(followAccountSuccess(response.data, alreadyFollowing));
}).catch(error => { }).catch(error => {
dispatch(followAccountFail(error, locked)); dispatch(followAccountFail(error, locked));

View file

@ -73,7 +73,7 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
let filtered = false; let filtered = false;
if (notification.type === 'mention') { if (['mention', 'status'].includes(notification.type)) {
const dropRegex = filters[0]; const dropRegex = filters[0];
const regex = filters[1]; const regex = filters[1];
const searchIndex = searchTextFromRawStatus(notification.status); const searchIndex = searchTextFromRawStatus(notification.status);

View file

@ -680,6 +680,7 @@ class Status extends ImmutablePureComponent {
favourite: 'favourited', favourite: 'favourited',
reblog: 'boosted', reblog: 'boosted',
reblogged_by: 'boosted', reblogged_by: 'boosted',
status: 'posted',
}[prepend]; }[prepend];
selectorAttribs[`data-${notifKind}-by`] = `@${account.get('acct')}`; selectorAttribs[`data-${notifKind}-by`] = `@${account.get('acct')}`;

View file

@ -64,6 +64,14 @@ export default class StatusPrepend extends React.PureComponent {
values={{ name : link }} values={{ name : link }}
/> />
); );
case 'status':
return (
<FormattedMessage
id='notification.status'
defaultMessage='{name} just posted'
values={{ name: link }}
/>
);
case 'poll': case 'poll':
if (me === account.get('id')) { if (me === account.get('id')) {
return ( return (
@ -88,12 +96,32 @@ export default class StatusPrepend extends React.PureComponent {
const { Message } = this; const { Message } = this;
const { type } = this.props; const { type } = this.props;
let iconId;
switch(type) {
case 'favourite':
iconId = 'star';
break;
case 'featured':
iconId = 'thumb-tack';
break;
case 'poll':
iconId = 'tasks';
break;
case 'reblogged_by':
iconId = 'retweet';
break;
case 'status':
iconId = 'bell';
break;
};
return !type ? null : ( return !type ? null : (
<aside className={type === 'reblogged_by' || type === 'featured' ? 'status__prepend' : 'notification__message'}> <aside className={type === 'reblogged_by' || type === 'featured' ? 'status__prepend' : 'notification__message'}>
<div className={type === 'reblogged_by' || type === 'featured' ? 'status__prepend-icon-wrapper' : 'notification__favourite-icon-wrapper'}> <div className={type === 'reblogged_by' || type === 'featured' ? 'status__prepend-icon-wrapper' : 'notification__favourite-icon-wrapper'}>
<Icon <Icon
className={`status__prepend-icon ${type === 'favourite' ? 'star-icon' : ''}`} className={`status__prepend-icon ${type === 'favourite' ? 'star-icon' : ''}`}
id={type === 'favourite' ? 'star' : (type === 'featured' ? 'thumb-tack' : (type === 'poll' ? 'tasks' : 'retweet'))} id={iconId}
/> />
</div> </div>
<Message /> <Message />

View file

@ -7,6 +7,7 @@ import { autoPlayGif, me, isStaff } from 'flavours/glitch/util/initial_state';
import { preferencesLink, profileLink, accountAdminLink } from 'flavours/glitch/util/backend_links'; import { preferencesLink, profileLink, accountAdminLink } from 'flavours/glitch/util/backend_links';
import classNames from 'classnames'; import classNames from 'classnames';
import Icon from 'flavours/glitch/components/icon'; import Icon from 'flavours/glitch/components/icon';
import IconButton from 'flavours/glitch/components/icon_button';
import Avatar from 'flavours/glitch/components/avatar'; import Avatar from 'flavours/glitch/components/avatar';
import Button from 'flavours/glitch/components/button'; import Button from 'flavours/glitch/components/button';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
@ -34,6 +35,8 @@ const messages = defineMessages({
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' }, unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' }, hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' },
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show 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' }, pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
@ -68,8 +71,9 @@ class Header extends ImmutablePureComponent {
onBlock: PropTypes.func.isRequired, onBlock: PropTypes.func.isRequired,
onMention: PropTypes.func.isRequired, onMention: PropTypes.func.isRequired,
onDirect: PropTypes.func.isRequired, onDirect: PropTypes.func.isRequired,
onReport: PropTypes.func.isRequired,
onReblogToggle: PropTypes.func.isRequired, onReblogToggle: PropTypes.func.isRequired,
onNotifyToggle: PropTypes.func.isRequired,
onReport: PropTypes.func.isRequired,
onMute: PropTypes.func.isRequired, onMute: PropTypes.func.isRequired,
onBlockDomain: PropTypes.func.isRequired, onBlockDomain: PropTypes.func.isRequired,
onUnblockDomain: PropTypes.func.isRequired, onUnblockDomain: PropTypes.func.isRequired,
@ -138,6 +142,7 @@ class Header extends ImmutablePureComponent {
let info = []; let info = [];
let actionBtn = ''; let actionBtn = '';
let bellBtn = '';
let lockedIcon = ''; let lockedIcon = '';
let menu = []; let menu = [];
@ -168,6 +173,10 @@ class Header extends ImmutablePureComponent {
actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.edit_profile)} onClick={this.openEditProfile} />; actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.edit_profile)} onClick={this.openEditProfile} />;
} }
if (account.getIn(['relationship', 'requested']) || account.getIn(['relationship', 'following'])) {
bellBtn = <IconButton icon='bell-o' size={24} active={account.getIn(['relationship', 'notifying'])} title={intl.formatMessage(account.getIn(['relationship', 'notifying']) ? messages.disableNotifications : messages.enableNotifications, { name: account.get('username') })} onClick={this.props.onNotifyToggle} />;
}
if (account.get('moved') && !account.getIn(['relationship', 'following'])) { if (account.get('moved') && !account.getIn(['relationship', 'following'])) {
actionBtn = ''; actionBtn = '';
} }
@ -289,6 +298,7 @@ class Header extends ImmutablePureComponent {
<div className='account__header__tabs__buttons'> <div className='account__header__tabs__buttons'>
{actionBtn} {actionBtn}
{bellBtn}
<DropdownMenuContainer items={menu} icon='ellipsis-v' size={24} direction='right' /> <DropdownMenuContainer items={menu} icon='ellipsis-v' size={24} direction='right' />
</div> </div>

View file

@ -56,6 +56,10 @@ export default class Header extends ImmutablePureComponent {
this.props.onReblogToggle(this.props.account); this.props.onReblogToggle(this.props.account);
} }
handleNotifyToggle = () => {
this.props.onNotifyToggle(this.props.account);
}
handleMute = () => { handleMute = () => {
this.props.onMute(this.props.account); this.props.onMute(this.props.account);
} }
@ -107,6 +111,7 @@ export default class Header extends ImmutablePureComponent {
onMention={this.handleMention} onMention={this.handleMention}
onDirect={this.handleDirect} onDirect={this.handleDirect}
onReblogToggle={this.handleReblogToggle} onReblogToggle={this.handleReblogToggle}
onNotifyToggle={this.handleNotifyToggle}
onReport={this.handleReport} onReport={this.handleReport}
onMute={this.handleMute} onMute={this.handleMute}
onBlockDomain={this.handleBlockDomain} onBlockDomain={this.handleBlockDomain}

View file

@ -81,9 +81,9 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
onReblogToggle (account) { onReblogToggle (account) {
if (account.getIn(['relationship', 'showing_reblogs'])) { if (account.getIn(['relationship', 'showing_reblogs'])) {
dispatch(followAccount(account.get('id'), false)); dispatch(followAccount(account.get('id'), { reblogs: false }));
} else { } else {
dispatch(followAccount(account.get('id'), true)); dispatch(followAccount(account.get('id'), { reblogs: true }));
} }
}, },
@ -95,6 +95,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) { onReport (account) {
dispatch(initReport(account)); dispatch(initReport(account));
}, },

View file

@ -9,6 +9,7 @@ const tooltips = defineMessages({
boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' }, boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' },
polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' }, polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' },
follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' }, follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },
statuses: { id: 'notifications.filter.statuses', defaultMessage: 'Updates from people you follow' },
}); });
export default @injectIntl export default @injectIntl
@ -87,6 +88,13 @@ class FilterBar extends React.PureComponent {
> >
<Icon id='tasks' fixedWidth /> <Icon id='tasks' fixedWidth />
</button> </button>
<button
className={selectedFilter === 'status' ? 'active' : ''}
onClick={this.onClick('status')}
title={intl.formatMessage(tooltips.statuses)}
>
<Icon id='home' fixedWidth />
</button>
<button <button
className={selectedFilter === 'follow' ? 'active' : ''} className={selectedFilter === 'follow' ? 'active' : ''}
onClick={this.onClick('follow')} onClick={this.onClick('follow')}

View file

@ -83,6 +83,28 @@ export default class Notification extends ImmutablePureComponent {
unread={this.props.unread} unread={this.props.unread}
/> />
); );
case 'status':
return (
<StatusContainer
containerId={notification.get('id')}
hidden={hidden}
id={notification.get('status')}
account={notification.get('account')}
prepend='status'
muted
notification={notification}
onMoveDown={onMoveDown}
onMoveUp={onMoveUp}
onMention={onMention}
getScrollPosition={getScrollPosition}
updateScrollBottom={updateScrollBottom}
cachedMediaWidth={this.props.cachedMediaWidth}
cacheMediaWidth={this.props.cacheMediaWidth}
onUnmount={this.props.onUnmount}
withDismiss
unread={this.props.unread}
/>
);
case 'favourite': case 'favourite':
return ( return (
<StatusContainer <StatusContainer

View file

@ -620,6 +620,10 @@
padding: 2px; padding: 2px;
} }
& > .icon-button {
margin-right: 8px;
}
.button { .button {
margin: 0 8px; margin: 0 8px;
} }