about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch/features
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours/glitch/features')
-rw-r--r--app/javascript/flavours/glitch/features/account_gallery/components/media_item.js40
-rw-r--r--app/javascript/flavours/glitch/features/account_gallery/index.js3
-rw-r--r--app/javascript/flavours/glitch/features/blocks/index.js3
-rw-r--r--app/javascript/flavours/glitch/features/favourites/index.js1
-rw-r--r--app/javascript/flavours/glitch/features/follow_requests/index.js1
-rw-r--r--app/javascript/flavours/glitch/features/followers/index.js1
-rw-r--r--app/javascript/flavours/glitch/features/following/index.js3
-rw-r--r--app/javascript/flavours/glitch/features/getting_started/index.js9
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/navigation/index.js8
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js8
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/page/index.js32
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/page/item/index.js95
-rw-r--r--app/javascript/flavours/glitch/features/mutes/index.js1
-rw-r--r--app/javascript/flavours/glitch/features/reblogs/index.js1
-rw-r--r--app/javascript/flavours/glitch/features/status/index.js18
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/video/index.js4
18 files changed, 149 insertions, 83 deletions
diff --git a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
index c2cf48d7b..89778e123 100644
--- a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
+++ b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
@@ -2,6 +2,7 @@ import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import Permalink from 'flavours/glitch/components/permalink';
+import { displayMedia } from 'flavours/glitch/util/initial_state';
 
 export default class MediaItem extends ImmutablePureComponent {
 
@@ -9,8 +10,22 @@ export default class MediaItem extends ImmutablePureComponent {
     media: ImmutablePropTypes.map.isRequired,
   };
 
+  state = {
+    visible: displayMedia !== 'hide_all' && !this.props.media.getIn(['status', 'sensitive']) || displayMedia === 'show_all',
+  };
+
+  handleClick = () => {
+    if (!this.state.visible) {
+      this.setState({ visible: true });
+      return true;
+    }
+
+    return false;
+  }
+
   render () {
     const { media } = this.props;
+    const { visible } = this.state;
     const status = media.get('status');
     const focusX = media.getIn(['meta', 'focus', 'x']);
     const focusY = media.getIn(['meta', 'focus', 'y']);
@@ -18,21 +33,36 @@ export default class MediaItem extends ImmutablePureComponent {
     const y = ((focusY / -2) + .5) * 100;
     const style = {};
 
-    let content;
+    let label, icon, title;
 
     if (media.get('type') === 'gifv') {
-      content = <span className='media-gallery__gifv__label'>GIF</span>;
+      label = <span className='media-gallery__gifv__label'>GIF</span>;
     }
 
-    if (!status.get('sensitive')) {
+    if (visible) {
       style.backgroundImage    = `url(${media.get('preview_url')})`;
       style.backgroundPosition = `${x}% ${y}%`;
+      title                    = media.get('description');
+    } else {
+      icon = (
+        <span className='account-gallery__item__icons'>
+          <i className='fa fa-eye-slash' />
+        </span>
+      );
+      title = status.get('spoiler_text') || media.get('description');
     }
 
     return (
       <div className='account-gallery__item'>
-        <Permalink to={`/statuses/${status.get('id')}`} href={status.get('url')} style={style}>
-          {content}
+        <Permalink
+          to={`/statuses/${status.get('id')}`}
+          href={status.get('url')}
+          style={style}
+          title={title}
+          onInterceptClick={this.handleClick}
+        >
+          {icon}
+          {label}
         </Permalink>
       </div>
     );
diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js
index de8318964..53b906d16 100644
--- a/app/javascript/flavours/glitch/features/account_gallery/index.js
+++ b/app/javascript/flavours/glitch/features/account_gallery/index.js
@@ -90,7 +90,8 @@ export default class AccountGallery extends ImmutablePureComponent {
   }
 
   shouldUpdateScroll = (prevRouterProps, { location }) => {
-    return !(location.state && location.state.mastodonModalOpen)
+    if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false;
+    return !(location.state && location.state.mastodonModalOpen);
   }
 
   render () {
diff --git a/app/javascript/flavours/glitch/features/blocks/index.js b/app/javascript/flavours/glitch/features/blocks/index.js
index 4c8b16504..386a0ce63 100644
--- a/app/javascript/flavours/glitch/features/blocks/index.js
+++ b/app/javascript/flavours/glitch/features/blocks/index.js
@@ -43,7 +43,8 @@ export default class Blocks extends ImmutablePureComponent {
   }
 
   shouldUpdateScroll = (prevRouterProps, { location }) => {
-    return !(location.state && location.state.mastodonModalOpen)
+    if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false;
+    return !(location.state && location.state.mastodonModalOpen);
   }
 
   render () {
diff --git a/app/javascript/flavours/glitch/features/favourites/index.js b/app/javascript/flavours/glitch/features/favourites/index.js
index cf8b31eb3..65cd4a19b 100644
--- a/app/javascript/flavours/glitch/features/favourites/index.js
+++ b/app/javascript/flavours/glitch/features/favourites/index.js
@@ -34,6 +34,7 @@ export default class Favourites extends ImmutablePureComponent {
   }
 
   shouldUpdateScroll = (prevRouterProps, { location }) => {
+    if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false;
     return !(location.state && location.state.mastodonModalOpen);
   }
 
diff --git a/app/javascript/flavours/glitch/features/follow_requests/index.js b/app/javascript/flavours/glitch/features/follow_requests/index.js
index 1e4633984..bce6338ea 100644
--- a/app/javascript/flavours/glitch/features/follow_requests/index.js
+++ b/app/javascript/flavours/glitch/features/follow_requests/index.js
@@ -43,6 +43,7 @@ export default class FollowRequests extends ImmutablePureComponent {
   }
 
   shouldUpdateScroll = (prevRouterProps, { location }) => {
+    if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false;
     return !(location.state && location.state.mastodonModalOpen);
   }
 
diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js
index cdde1775c..a977142ed 100644
--- a/app/javascript/flavours/glitch/features/followers/index.js
+++ b/app/javascript/flavours/glitch/features/followers/index.js
@@ -57,6 +57,7 @@ export default class Followers extends ImmutablePureComponent {
   }
 
   shouldUpdateScroll = (prevRouterProps, { location }) => {
+    if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false;
     return !(location.state && location.state.mastodonModalOpen);
   }
 
diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js
index e7a72d036..70aeefaad 100644
--- a/app/javascript/flavours/glitch/features/following/index.js
+++ b/app/javascript/flavours/glitch/features/following/index.js
@@ -57,7 +57,8 @@ export default class Following extends ImmutablePureComponent {
   }
 
   shouldUpdateScroll = (prevRouterProps, { location }) => {
-    return !(location.state && location.state.mastodonModalOpen)
+    if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false;
+    return !(location.state && location.state.mastodonModalOpen);
   }
 
   render () {
diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js
index 09dcbe716..c1897cc33 100644
--- a/app/javascript/flavours/glitch/features/getting_started/index.js
+++ b/app/javascript/flavours/glitch/features/getting_started/index.js
@@ -165,13 +165,10 @@ export default class GettingStarted extends ImmutablePureComponent {
           <div className='getting-started__footer'>
             <div className='static-content getting-started'>
               <p>
-                <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md' rel='noopener' target='_blank'>
-                  <FormattedMessage id='getting_started.faq' defaultMessage='FAQ' />
+                <a href='https://docs.joinmastodon.org' target='_blank'>
+                  <FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' />
                 </a>&nbsp;•&nbsp;
-                <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md' rel='noopener' target='_blank'>
-                  <FormattedMessage id='getting_started.userguide' defaultMessage='User Guide' />
-                </a>&nbsp;•&nbsp;
-                <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' rel='noopener' target='_blank'>
+                <a href='https://joinmastodon.org/apps' target='_blank' rel='noopener'>
                   <FormattedMessage id='getting_started.appsshort' defaultMessage='Apps' />
                 </a>
               </p>
diff --git a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
index a992b1ffc..cf02101cf 100644
--- a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
@@ -38,37 +38,42 @@ export default class LocalSettingsNavigation extends React.PureComponent {
           active={index === 0}
           index={0}
           onNavigate={onNavigate}
+          icon='cogs'
           title={intl.formatMessage(messages.general)}
         />
         <LocalSettingsNavigationItem
           active={index === 1}
           index={1}
           onNavigate={onNavigate}
+          icon='pencil'
           title={intl.formatMessage(messages.compose)}
         />
         <LocalSettingsNavigationItem
           active={index === 2}
           index={2}
           onNavigate={onNavigate}
+          textIcon='CW'
           title={intl.formatMessage(messages.content_warnings)}
         />
         <LocalSettingsNavigationItem
           active={index === 3}
           index={3}
           onNavigate={onNavigate}
+          icon='angle-double-up'
           title={intl.formatMessage(messages.collapsed)}
         />
         <LocalSettingsNavigationItem
           active={index === 4}
           index={4}
           onNavigate={onNavigate}
+          icon='image'
           title={intl.formatMessage(messages.media)}
         />
         <LocalSettingsNavigationItem
           active={index === 5}
           href='/settings/preferences'
           index={5}
-          icon='cog'
+          icon='sliders'
           title={intl.formatMessage(messages.preferences)}
         />
         <LocalSettingsNavigationItem
@@ -76,6 +81,7 @@ export default class LocalSettingsNavigation extends React.PureComponent {
           className='close'
           index={6}
           onNavigate={onClose}
+          icon='times'
           title={intl.formatMessage(messages.close)}
         />
       </nav>
diff --git a/app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js
index b67d479e7..68a998b6c 100644
--- a/app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js
@@ -12,6 +12,7 @@ export default class LocalSettingsPage extends React.PureComponent {
     className: PropTypes.string,
     href: PropTypes.string,
     icon: PropTypes.string,
+    textIcon: PropTypes.string,
     index: PropTypes.number.isRequired,
     onNavigate: PropTypes.func,
     title: PropTypes.string,
@@ -32,6 +33,7 @@ export default class LocalSettingsPage extends React.PureComponent {
       className,
       href,
       icon,
+      textIcon,
       onNavigate,
       title,
     } = this.props;
@@ -40,14 +42,14 @@ export default class LocalSettingsPage extends React.PureComponent {
       active,
     }, className);
 
-    const iconElem = icon ? <i className={`fa fa-fw fa-${icon}`} /> : null;
+    const iconElem = icon ? <i className={`fa fa-fw fa-${icon}`} /> : (textIcon ? <span className='text-icon-button'>{textIcon}</span> : null);
 
     if (href) return (
       <a
         href={href}
         className={finalClassName}
       >
-        {iconElem} {title}
+        {iconElem} <span>{title}</span>
       </a>
     );
     else if (onNavigate) return (
@@ -57,7 +59,7 @@ export default class LocalSettingsPage extends React.PureComponent {
         tabIndex='0'
         className={finalClassName}
       >
-        {iconElem} {title}
+        {iconElem} <span>{title}</span>
       </a>
     );
     else return null;
diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js
index ece80c4da..4f1b8525f 100644
--- a/app/javascript/flavours/glitch/features/local_settings/page/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js
@@ -50,7 +50,8 @@ export default class LocalSettingsPage extends React.PureComponent {
             id='mastodon-settings--notifications-tab_badge'
             onChange={onChange}
           >
-            <FormattedMessage id='settings.notifications.tab_badge' defaultMessage="Display a badge for unread notifications if the notifications column isn't open" />
+            <FormattedMessage id='settings.notifications.tab_badge' defaultMessage="Unread notifications badge" />
+            <span className='hint'><FormattedMessage id='settings.notifications.tab_badge.hint' defaultMessage="Display a badge for unread notifications in the column icons when the notifications column isn't open" /></span>
           </LocalSettingsPageItem>
           <LocalSettingsPageItem
             settings={settings}
@@ -58,7 +59,8 @@ export default class LocalSettingsPage extends React.PureComponent {
             id='mastodon-settings--notifications-favicon_badge'
             onChange={onChange}
           >
-            <FormattedMessage id='settings.notifications.favicon_badge' defaultMessage='Display unread notifications count in the favicon' />
+            <FormattedMessage id='settings.notifications.favicon_badge' defaultMessage='Unread notifications favicon badge' />
+            <span className='hint'><FormattedMessage id='settings.notifications.favicon_badge.hint' defaultMessage="Add a badge for unread notifications to the favicon" /></span>
           </LocalSettingsPageItem>
         </section>
         <section>
@@ -83,6 +85,7 @@ export default class LocalSettingsPage extends React.PureComponent {
             onChange={onChange}
           >
             <FormattedMessage id='settings.wide_view' defaultMessage='Wide view (Desktop mode only)' />
+            <span className='hint'><FormattedMessage id='settings.wide_view_hint' defaultMessage='Stretches columns to better fill the available space.' /></span>
           </LocalSettingsPageItem>
           <LocalSettingsPageItem
             settings={settings}
@@ -112,7 +115,8 @@ export default class LocalSettingsPage extends React.PureComponent {
           id='mastodon-settings--preselect_on_reply'
           onChange={onChange}
         >
-          <FormattedMessage id='settings.preselect_on_reply' defaultMessage='Pre-select usernames past the first when replying to a toot with multiple participants' />
+          <FormattedMessage id='settings.preselect_on_reply' defaultMessage='Pre-select usernames on reply' />
+          <span className='hint'><FormattedMessage id='settings.preselect_on_reply_hint' defaultMessage='When replying to a conversation with multiple participants, pre-select usernames past the first' /></span>
         </LocalSettingsPageItem>
         <LocalSettingsPageItem
           settings={settings}
@@ -186,6 +190,15 @@ export default class LocalSettingsPage extends React.PureComponent {
         >
           <FormattedMessage id='settings.enable_collapsed' defaultMessage='Enable collapsed toots' />
         </LocalSettingsPageItem>
+        <LocalSettingsPageItem
+          settings={settings}
+          item={['collapsed', 'show_action_bar']}
+          id='mastodon-settings--collapsed-show-action-bar'
+          onChange={onChange}
+          dependsOn={[['collapsed', 'enabled']]}
+        >
+          <FormattedMessage id='settings.show_action_bar' defaultMessage='Show action buttons in collapsed toots' />
+        </LocalSettingsPageItem>
         <section>
           <h2><FormattedMessage id='settings.auto_collapse' defaultMessage='Automatic collapsing' /></h2>
           <LocalSettingsPageItem
@@ -269,18 +282,6 @@ export default class LocalSettingsPage extends React.PureComponent {
             <FormattedMessage id='settings.image_backgrounds_media' defaultMessage='Preview collapsed toot media' />
           </LocalSettingsPageItem>
         </section>
-        <section>
-          <h2></h2>
-          <LocalSettingsPageItem
-            settings={settings}
-            item={['collapsed', 'show_action_bar']}
-            id='mastodon-settings--collapsed-show-action-bar'
-            onChange={onChange}
-            dependsOn={[['collapsed', 'enabled']]}
-          >
-            <FormattedMessage id='settings.show_action_bar' defaultMessage='Show action buttons in collapsed toots' />
-          </LocalSettingsPageItem>
-        </section>
       </div>
     ),
     ({ onChange, settings }) => (
@@ -293,6 +294,7 @@ export default class LocalSettingsPage extends React.PureComponent {
           onChange={onChange}
         >
           <FormattedMessage id='settings.media_letterbox' defaultMessage='Letterbox media' />
+          <span className='hint'><FormattedMessage id='settings.media_letterbox_hint' defaultMessage='Scale down and letterbox media to fill the image containers instead of stretching and cropping them' /></span>
         </LocalSettingsPageItem>
         <LocalSettingsPageItem
           settings={settings}
diff --git a/app/javascript/flavours/glitch/features/local_settings/page/item/index.js b/app/javascript/flavours/glitch/features/local_settings/page/item/index.js
index fe237f11e..66b937365 100644
--- a/app/javascript/flavours/glitch/features/local_settings/page/item/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/page/item/index.js
@@ -17,6 +17,7 @@ export default class LocalSettingsPageItem extends React.PureComponent {
     options: PropTypes.arrayOf(PropTypes.shape({
       value: PropTypes.string.isRequired,
       message: PropTypes.string.isRequired,
+      hint: PropTypes.string,
     })),
     settings: ImmutablePropTypes.map.isRequired,
     placeholder: PropTypes.string,
@@ -48,57 +49,63 @@ export default class LocalSettingsPageItem extends React.PureComponent {
 
     if (options && options.length > 0) {
       const currentValue = settings.getIn(item);
-      const optionElems = options && options.length > 0 && options.map((opt) => (
-        <option
-          key={opt.value}
-          value={opt.value}
-        >
-          {opt.message}
-        </option>
-      ));
-      return (
-        <label className='glitch local-settings__page__item' htmlFor={id}>
-          <p>{children}</p>
-          <p>
-            <select
-              id={id}
-              disabled={!enabled}
+      const optionElems = options && options.length > 0 && options.map((opt) => {
+        let optionId = `${id}--${opt.value}`;
+        return (
+          <label htmlFor={optionId}>
+            <input type='radio'
+              name={id}
+              id={optionId}
+              value={opt.value}
               onBlur={handleChange}
               onChange={handleChange}
-              value={currentValue}
-            >
-              {optionElems}
-            </select>
-          </p>
-        </label>
+              checked={ currentValue === opt.value }
+              disabled={!enabled}
+            />
+            {opt.message}
+            {opt.hint && <span class='hint'>{opt.hint}</span>}
+          </label>
+        );
+      });
+      return (
+        <div class='glitch local-settings__page__item radio_buttons'>
+          <fieldset>
+            <legend>{children}</legend>
+            {optionElems}
+          </fieldset>
+        </div>
       );
     } else if (placeholder) {
       return (
-        <label className='glitch local-settings__page__item' htmlFor={id}>
-          <p>{children}</p>
-          <p>
-            <input
-              id={id}
-              type='text'
-              value={settings.getIn(item)}
-              placeholder={placeholder}
-              onChange={handleChange}
-              disabled={!enabled}
-            />
-          </p>
-        </label>
+        <div className='glitch local-settings__page__item string'>
+          <label htmlFor={id}>
+            <p>{children}</p>
+            <p>
+              <input
+                id={id}
+                type='text'
+                value={settings.getIn(item)}
+                placeholder={placeholder}
+                onChange={handleChange}
+                disabled={!enabled}
+              />
+            </p>
+          </label>
+        </div>
       );
     } else return (
-      <label className='glitch local-settings__page__item' htmlFor={id}>
-        <input
-          id={id}
-          type='checkbox'
-          checked={settings.getIn(item)}
-          onChange={handleChange}
-          disabled={!enabled}
-        />
-        {children}
-      </label>
+      <div className='glitch local-settings__page__item boolean'>
+        <label htmlFor={id}>
+          <input
+            id={id}
+            type='checkbox'
+            checked={settings.getIn(item)}
+            onChange={handleChange}
+            disabled={!enabled}
+          />
+          {children}
+        </label>
+      </div>
     );
   }
 
diff --git a/app/javascript/flavours/glitch/features/mutes/index.js b/app/javascript/flavours/glitch/features/mutes/index.js
index d94c1d8ad..bbcbea701 100644
--- a/app/javascript/flavours/glitch/features/mutes/index.js
+++ b/app/javascript/flavours/glitch/features/mutes/index.js
@@ -43,6 +43,7 @@ export default class Mutes extends ImmutablePureComponent {
   }
 
   shouldUpdateScroll = (prevRouterProps, { location }) => {
+    if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false;
     return !(location.state && location.state.mastodonModalOpen);
   }
 
diff --git a/app/javascript/flavours/glitch/features/reblogs/index.js b/app/javascript/flavours/glitch/features/reblogs/index.js
index c0a65d1de..75f8390a1 100644
--- a/app/javascript/flavours/glitch/features/reblogs/index.js
+++ b/app/javascript/flavours/glitch/features/reblogs/index.js
@@ -34,6 +34,7 @@ export default class Reblogs extends ImmutablePureComponent {
   }
 
   shouldUpdateScroll = (prevRouterProps, { location }) => {
+    if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false;
     return !(location.state && location.state.mastodonModalOpen);
   }
 
diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js
index 5759a575c..4382748d5 100644
--- a/app/javascript/flavours/glitch/features/status/index.js
+++ b/app/javascript/flavours/glitch/features/status/index.js
@@ -50,6 +50,8 @@ const messages = defineMessages({
   revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },
   hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },
   detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' },
+  replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
+  replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
 });
 
 const makeMapStateToProps = () => {
@@ -60,6 +62,7 @@ const makeMapStateToProps = () => {
     settings: state.get('local_settings'),
     ancestorsIds: state.getIn(['contexts', 'ancestors', props.params.statusId]),
     descendantsIds: state.getIn(['contexts', 'descendants', props.params.statusId]),
+    askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
   });
 
   return mapStateToProps;
@@ -81,6 +84,7 @@ export default class Status extends ImmutablePureComponent {
     ancestorsIds: ImmutablePropTypes.list,
     descendantsIds: ImmutablePropTypes.list,
     intl: PropTypes.object.isRequired,
+    askReplyConfirmation: PropTypes.bool,
   };
 
   state = {
@@ -140,7 +144,16 @@ export default class Status extends ImmutablePureComponent {
   }
 
   handleReplyClick = (status) => {
-    this.props.dispatch(replyCompose(status, this.context.router.history));
+    let { askReplyConfirmation, dispatch, intl } = this.props;
+    if (askReplyConfirmation) {
+      dispatch(openModal('CONFIRM', {
+        message: intl.formatMessage(messages.replyMessage),
+        confirm: intl.formatMessage(messages.replyConfirm),
+        onConfirm: () => dispatch(replyCompose(status, this.context.router.history)),
+      }));
+    } else {
+      dispatch(replyCompose(status, this.context.router.history));
+    }
   }
 
   handleModalReblog = (status) => {
@@ -351,7 +364,8 @@ export default class Status extends ImmutablePureComponent {
   }
 
   shouldUpdateScroll = (prevRouterProps, { location }) => {
-    return !(location.state && location.state.mastodonModalOpen)
+    if ((((prevRouterProps || {}).location || {}).state || {}).mastodonModalOpen) return false;
+    return !(location.state && location.state.mastodonModalOpen);
   }
 
   render () {
diff --git a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
index 4c910daec..16355a446 100644
--- a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
@@ -133,7 +133,7 @@ const PageSix = ({ admin, domain }) => {
       <h1><FormattedMessage id='onboarding.page_six.almost_done' defaultMessage='Almost done...' /></h1>
       {adminSection}
       <p><FormattedMessage id='onboarding.page_six.github' defaultMessage='{domain} runs on Glitchsoc. Glitchsoc is a friendly {fork} of {Mastodon}. Glitchsoc is fully compatible with all Mastodon apps and instances. Glitchsoc is free open-source software. You can report bugs, request features, or contribute to the code on {github}.' values={{ domain, fork: <a href='https://en.wikipedia.org/wiki/Fork_(software_development)' target='_blank' rel='noopener'>fork</a>, Mastodon: <a href='https://github.com/tootsuite/mastodon' target='_blank' rel='noopener'>Mastodon</a>, github: <a href='https://github.com/glitch-soc/mastodon' target='_blank' rel='noopener'>GitHub</a> }} /></p>
-      <p><FormattedMessage id='onboarding.page_six.apps_available' defaultMessage='There are {apps} available for iOS, Android and other platforms.' values={{ domain, apps: <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' target='_blank' rel='noopener'><FormattedMessage id='onboarding.page_six.various_app' defaultMessage='mobile apps' /></a> }} /></p>
+      <p><FormattedMessage id='onboarding.page_six.apps_available' defaultMessage='There are {apps} available for iOS, Android and other platforms.' values={{ domain, apps: <a href='https://joinmastodon.org/apps' target='_blank' rel='noopener'><FormattedMessage id='onboarding.page_six.various_app' defaultMessage='mobile apps' /></a> }} /></p>
       <p><em><FormattedMessage id='onboarding.page_six.appetoot' defaultMessage='Bon Appetoot!' /></em></p>
     </div>
   );
diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js
index ecbac1f8f..510bb9540 100644
--- a/app/javascript/flavours/glitch/features/ui/index.js
+++ b/app/javascript/flavours/glitch/features/ui/index.js
@@ -456,7 +456,7 @@ export default class UI extends React.Component {
     };
 
     return (
-      <HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef}>
+      <HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused>
         <div className={className} ref={this.setRef} style={{ pointerEvents: dropdownMenuIsOpen ? 'none' : null }}>
           {navbarUnder ? null : (<TabsBar />)}
 
diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js
index 5cbe01f26..227f298e4 100644
--- a/app/javascript/flavours/glitch/features/video/index.js
+++ b/app/javascript/flavours/glitch/features/video/index.js
@@ -5,7 +5,7 @@ import { fromJS } from 'immutable';
 import { throttle } from 'lodash';
 import classNames from 'classnames';
 import { isFullscreen, requestFullscreen, exitFullscreen } from 'flavours/glitch/util/fullscreen';
-import { displaySensitiveMedia } from 'flavours/glitch/util/initial_state';
+import { displayMedia } from 'flavours/glitch/util/initial_state';
 
 const messages = defineMessages({
   play: { id: 'video.play', defaultMessage: 'Play' },
@@ -114,7 +114,7 @@ export default class Video extends React.PureComponent {
     fullscreen: false,
     hovered: false,
     muted: false,
-    revealed: this.props.revealed === undefined ? (!this.props.sensitive || displaySensitiveMedia) : this.props.revealed,
+    revealed: this.props.revealed === undefined ? (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all') : this.props.revealed,
   };
 
   setPlayerRef = c => {