about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2020-09-18 17:26:45 +0200
committerThibaut Girka <thib@sitedethib.com>2020-09-28 17:49:55 +0200
commit14869ee656d03313882a912978e5478c628512f3 (patch)
tree02d4476231fe56d0840bf50fdbcf6ca1d1622dee
parent0a069bffd9d1318f5a1b28f03afe92e96a61fdf3 (diff)
[Glitch] Add option to be notified when a followed user posts
Port 974b1b79ce58e6799e5e5bb576e630ca783150de to glitch-soc

Signed-off-by: Thibaut Girka <thib@sitedethib.com>
-rw-r--r--app/javascript/flavours/glitch/actions/accounts.js4
-rw-r--r--app/javascript/flavours/glitch/actions/notifications.js2
-rw-r--r--app/javascript/flavours/glitch/components/status.js1
-rw-r--r--app/javascript/flavours/glitch/components/status_prepend.js30
-rw-r--r--app/javascript/flavours/glitch/features/account/components/header.js12
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/components/header.js5
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js12
-rw-r--r--app/javascript/flavours/glitch/features/notifications/components/filter_bar.js8
-rw-r--r--app/javascript/flavours/glitch/features/notifications/components/notification.js22
-rw-r--r--app/javascript/flavours/glitch/styles/components/accounts.scss4
10 files changed, 93 insertions, 7 deletions
diff --git a/app/javascript/flavours/glitch/actions/accounts.js b/app/javascript/flavours/glitch/actions/accounts.js
index 1b4bff487..428b62f68 100644
--- a/app/javascript/flavours/glitch/actions/accounts.js
+++ b/app/javascript/flavours/glitch/actions/accounts.js
@@ -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) => {
     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/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js
index ccc427c29..7f311153b 100644
--- a/app/javascript/flavours/glitch/actions/notifications.js
+++ b/app/javascript/flavours/glitch/actions/notifications.js
@@ -73,7 +73,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/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js
index 8da5db961..fc7940e5a 100644
--- a/app/javascript/flavours/glitch/components/status.js
+++ b/app/javascript/flavours/glitch/components/status.js
@@ -680,6 +680,7 @@ class Status extends ImmutablePureComponent {
         favourite: 'favourited',
         reblog: 'boosted',
         reblogged_by: 'boosted',
+        status: 'posted',
       }[prepend];
 
       selectorAttribs[`data-${notifKind}-by`] = `@${account.get('acct')}`;
diff --git a/app/javascript/flavours/glitch/components/status_prepend.js b/app/javascript/flavours/glitch/components/status_prepend.js
index 637c4f23a..0ba55d5d8 100644
--- a/app/javascript/flavours/glitch/components/status_prepend.js
+++ b/app/javascript/flavours/glitch/components/status_prepend.js
@@ -64,6 +64,14 @@ export default class StatusPrepend extends React.PureComponent {
           values={{ name : link }}
         />
       );
+    case 'status':
+      return (
+        <FormattedMessage
+          id='notification.status'
+          defaultMessage='{name} just posted'
+          values={{ name: link }}
+        />
+      );
     case 'poll':
       if (me === account.get('id')) {
         return (
@@ -88,12 +96,32 @@ export default class StatusPrepend extends React.PureComponent {
     const { Message } = this;
     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 : (
       <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'}>
           <Icon
             className={`status__prepend-icon ${type === 'favourite' ? 'star-icon' : ''}`}
-            id={type === 'favourite' ? 'star' : (type === 'featured' ? 'thumb-tack' : (type === 'poll' ? 'tasks' : 'retweet'))}
+            id={iconId}
           />
         </div>
         <Message />
diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js
index 88c578b59..9b080a14e 100644
--- a/app/javascript/flavours/glitch/features/account/components/header.js
+++ b/app/javascript/flavours/glitch/features/account/components/header.js
@@ -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 classNames from 'classnames';
 import Icon from 'flavours/glitch/components/icon';
+import IconButton from 'flavours/glitch/components/icon_button';
 import Avatar from 'flavours/glitch/components/avatar';
 import Button from 'flavours/glitch/components/button';
 import { NavLink } from 'react-router-dom';
@@ -34,6 +35,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,
@@ -138,6 +142,7 @@ class Header extends ImmutablePureComponent {
 
     let info        = [];
     let actionBtn   = '';
+    let bellBtn     = '';
     let lockedIcon  = '';
     let menu        = [];
 
@@ -168,6 +173,10 @@ class Header extends ImmutablePureComponent {
       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'])) {
       actionBtn = '';
     }
@@ -289,6 +298,7 @@ class Header extends ImmutablePureComponent {
 
             <div className='account__header__tabs__buttons'>
               {actionBtn}
+              {bellBtn}
 
               <DropdownMenuContainer items={menu} icon='ellipsis-v' size={24} direction='right' />
             </div>
diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/header.js b/app/javascript/flavours/glitch/features/account_timeline/components/header.js
index 8195735a1..a6b57d331 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/components/header.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/components/header.js
@@ -56,6 +56,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);
   }
@@ -107,6 +111,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/flavours/glitch/features/account_timeline/containers/header_container.js b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
index 225910292..90e746679 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
@@ -81,9 +81,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 }));
     }
   },
 
@@ -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) {
     dispatch(initReport(account));
   },
diff --git a/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js b/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js
index 6118305d6..c1de0f90e 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js
+++ b/app/javascript/flavours/glitch/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
@@ -88,6 +89,13 @@ class FilterBar extends React.PureComponent {
           <Icon id='tasks' fixedWidth />
         </button>
         <button
+          className={selectedFilter === 'status' ? 'active' : ''}
+          onClick={this.onClick('status')}
+          title={intl.formatMessage(tooltips.statuses)}
+        >
+          <Icon id='home' fixedWidth />
+        </button>
+        <button
           className={selectedFilter === 'follow' ? 'active' : ''}
           onClick={this.onClick('follow')}
           title={intl.formatMessage(tooltips.follows)}
diff --git a/app/javascript/flavours/glitch/features/notifications/components/notification.js b/app/javascript/flavours/glitch/features/notifications/components/notification.js
index bd415856c..e1d9fbd0a 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/notification.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/notification.js
@@ -83,6 +83,28 @@ export default class Notification extends ImmutablePureComponent {
           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':
       return (
         <StatusContainer
diff --git a/app/javascript/flavours/glitch/styles/components/accounts.scss b/app/javascript/flavours/glitch/styles/components/accounts.scss
index 0fc2a11ff..145219fa7 100644
--- a/app/javascript/flavours/glitch/styles/components/accounts.scss
+++ b/app/javascript/flavours/glitch/styles/components/accounts.scss
@@ -620,6 +620,10 @@
         padding: 2px;
       }
 
+      & > .icon-button {
+        margin-right: 8px;
+      }
+
       .button {
         margin: 0 8px;
       }