about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2022-03-09 21:15:24 +0100
committerGitHub <noreply@github.com>2022-03-09 21:15:24 +0100
commit9f2791eb64d5d19418561270f79071c185876d20 (patch)
treeebf96dada0dd70f7589b0b3cadac778a3df8aacd
parent2a56a890dabb7cffd1dc14cf8a7aea9cccc7ab09 (diff)
Add polls and media attachments to edit comparison modal in web UI (#17727)
-rw-r--r--app/javascript/mastodon/components/media_attachments.js116
-rw-r--r--app/javascript/mastodon/features/report/components/status_check_box.js52
-rw-r--r--app/javascript/mastodon/features/ui/components/compare_history_modal.js20
-rw-r--r--app/javascript/styles/mastodon/components.scss8
-rw-r--r--app/models/status_edit.rb7
5 files changed, 154 insertions, 49 deletions
diff --git a/app/javascript/mastodon/components/media_attachments.js b/app/javascript/mastodon/components/media_attachments.js
new file mode 100644
index 000000000..d27720de4
--- /dev/null
+++ b/app/javascript/mastodon/components/media_attachments.js
@@ -0,0 +1,116 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import { MediaGallery, Video, Audio } from 'mastodon/features/ui/util/async-components';
+import Bundle from 'mastodon/features/ui/components/bundle';
+import noop from 'lodash/noop';
+
+export default class MediaAttachments extends ImmutablePureComponent {
+
+  static propTypes = {
+    status: ImmutablePropTypes.map.isRequired,
+    height: PropTypes.number,
+    width: PropTypes.number,
+  };
+
+  static defaultProps = {
+    height: 110,
+    width: 239,
+  };
+
+  updateOnProps = [
+    'status',
+  ];
+
+  renderLoadingMediaGallery = () => {
+    const { height, width } = this.props;
+
+    return (
+      <div className='media-gallery' style={{ height, width }} />
+    );
+  }
+
+  renderLoadingVideoPlayer = () => {
+    const { height, width } = this.props;
+
+    return (
+      <div className='video-player' style={{ height, width }} />
+    );
+  }
+
+  renderLoadingAudioPlayer = () => {
+    const { height, width } = this.props;
+
+    return (
+      <div className='audio-player' style={{ height, width }} />
+    );
+  }
+
+  render () {
+    const { status, width, height } = this.props;
+    const mediaAttachments = status.get('media_attachments');
+
+    if (mediaAttachments.size === 0) {
+      return null;
+    }
+
+    if (mediaAttachments.getIn([0, 'type']) === 'audio') {
+      const audio = mediaAttachments.get(0);
+
+      return (
+        <Bundle fetchComponent={Audio} loading={this.renderLoadingAudioPlayer} >
+          {Component => (
+            <Component
+              src={audio.get('url')}
+              alt={audio.get('description')}
+              width={width}
+              height={height}
+              poster={audio.get('preview_url') || status.getIn(['account', 'avatar_static'])}
+              backgroundColor={audio.getIn(['meta', 'colors', 'background'])}
+              foregroundColor={audio.getIn(['meta', 'colors', 'foreground'])}
+              accentColor={audio.getIn(['meta', 'colors', 'accent'])}
+              duration={audio.getIn(['meta', 'original', 'duration'], 0)}
+            />
+          )}
+        </Bundle>
+      );
+    } else if (mediaAttachments.getIn([0, 'type']) === 'video') {
+      const video = mediaAttachments.get(0);
+
+      return (
+        <Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer} >
+          {Component => (
+            <Component
+              preview={video.get('preview_url')}
+              frameRate={video.getIn(['meta', 'original', 'frame_rate'])}
+              blurhash={video.get('blurhash')}
+              src={video.get('url')}
+              alt={video.get('description')}
+              width={width}
+              height={height}
+              inline
+              sensitive={status.get('sensitive')}
+              onOpenVideo={noop}
+            />
+          )}
+        </Bundle>
+      );
+    } else {
+      return (
+        <Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery} >
+          {Component => (
+            <Component
+              media={mediaAttachments}
+              sensitive={status.get('sensitive')}
+              defaultWidth={width}
+              height={height}
+              onOpenMedia={noop}
+            />
+          )}
+        </Bundle>
+      );
+    }
+  }
+
+}
diff --git a/app/javascript/mastodon/features/report/components/status_check_box.js b/app/javascript/mastodon/features/report/components/status_check_box.js
index a2eb3d6f5..373c60e21 100644
--- a/app/javascript/mastodon/features/report/components/status_check_box.js
+++ b/app/javascript/mastodon/features/report/components/status_check_box.js
@@ -1,14 +1,12 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
-import noop from 'lodash/noop';
 import StatusContent from 'mastodon/components/status_content';
-import { MediaGallery, Video } from 'mastodon/features/ui/util/async-components';
-import Bundle from 'mastodon/features/ui/components/bundle';
 import Avatar from 'mastodon/components/avatar';
 import DisplayName from 'mastodon/components/display_name';
 import RelativeTimestamp from 'mastodon/components/relative_timestamp';
 import Option from './option';
+import MediaAttachments from 'mastodon/components/media_attachments';
 
 export default class StatusCheckBox extends React.PureComponent {
 
@@ -27,51 +25,10 @@ export default class StatusCheckBox extends React.PureComponent {
   render () {
     const { status, checked } = this.props;
 
-    let media = null;
-
     if (status.get('reblog')) {
       return null;
     }
 
-    if (status.get('media_attachments').size > 0) {
-      if (status.get('media_attachments').some(item => item.get('type') === 'unknown')) {
-
-      } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
-        const video = status.getIn(['media_attachments', 0]);
-
-        media = (
-          <Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer} >
-            {Component => (
-              <Component
-                preview={video.get('preview_url')}
-                blurhash={video.get('blurhash')}
-                src={video.get('url')}
-                alt={video.get('description')}
-                width={239}
-                height={110}
-                inline
-                sensitive={status.get('sensitive')}
-                onOpenVideo={noop}
-              />
-            )}
-          </Bundle>
-        );
-      } else {
-        media = (
-          <Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery} >
-            {Component => (
-              <Component
-                media={status.get('media_attachments')}
-                sensitive={status.get('sensitive')}
-                height={110}
-                onOpenMedia={noop}
-              />
-            )}
-          </Bundle>
-        );
-      }
-    }
-
     const labelComponent = (
       <div className='status-check-box__status poll__option__text'>
         <div className='detailed-status__display-name'>
@@ -79,12 +36,13 @@ export default class StatusCheckBox extends React.PureComponent {
             <Avatar account={status.get('account')} size={46} />
           </div>
 
-          <div><DisplayName account={status.get('account')} /> · <RelativeTimestamp timestamp={status.get('created_at')} /></div>
+          <div>
+            <DisplayName account={status.get('account')} /> · <RelativeTimestamp timestamp={status.get('created_at')} />
+          </div>
         </div>
 
         <StatusContent status={status} />
-
-        {media}
+        <MediaAttachments status={status} />
       </div>
     );
 
diff --git a/app/javascript/mastodon/features/ui/components/compare_history_modal.js b/app/javascript/mastodon/features/ui/components/compare_history_modal.js
index 40cfba335..ecccc8f7d 100644
--- a/app/javascript/mastodon/features/ui/components/compare_history_modal.js
+++ b/app/javascript/mastodon/features/ui/components/compare_history_modal.js
@@ -9,6 +9,7 @@ import escapeTextContentForBrowser from 'escape-html';
 import InlineAccount from 'mastodon/components/inline_account';
 import IconButton from 'mastodon/components/icon_button';
 import RelativeTimestamp from 'mastodon/components/relative_timestamp';
+import MediaAttachments from 'mastodon/components/media_attachments';
 
 const mapStateToProps = (state, { statusId }) => ({
   versions: state.getIn(['history', statusId, 'items']),
@@ -70,6 +71,25 @@ class CompareHistoryModal extends React.PureComponent {
             )}
 
             <div className='status__content__text status__content__text--visible translate' dangerouslySetInnerHTML={content} />
+
+            {!!currentVersion.get('poll') && (
+              <div className='poll'>
+                <ul>
+                  {currentVersion.getIn(['poll', 'options']).map(option => (
+                    <li key={option.get('title')}>
+                      <span className='poll__input disabled' />
+
+                      <span
+                        className='poll__option__text translate'
+                        dangerouslySetInnerHTML={{ __html: emojify(escapeTextContentForBrowser(option.get('title')), emojiMap) }}
+                      />
+                    </li>
+                  ))}
+                </ul>
+              </div>
+            )}
+
+            <MediaAttachments status={currentVersion} />
           </div>
         </div>
       </div>
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 5d0d44b73..97587b62b 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -1127,7 +1127,7 @@
   .media-gallery,
   .audio-player,
   .video-player {
-    margin-top: 8px;
+    margin-top: 15px;
     max-width: 250px;
   }
 
@@ -5609,6 +5609,12 @@ a.status-card.compact:hover {
       margin: 20px 0;
     }
   }
+
+  .media-gallery,
+  .audio-player,
+  .video-player {
+    margin-top: 15px;
+  }
 }
 
 .loading-bar {
diff --git a/app/models/status_edit.rb b/app/models/status_edit.rb
index 6da9b4b85..e9c8fbe98 100644
--- a/app/models/status_edit.rb
+++ b/app/models/status_edit.rb
@@ -25,7 +25,12 @@ class StatusEdit < ApplicationRecord
 
   class PreservedMediaAttachment < ActiveModelSerializers::Model
     attributes :media_attachment, :description
-    delegate :id, :type, :url, :preview_url, :remote_url, :preview_remote_url, :text_url, :meta, :blurhash, to: :media_attachment
+
+    delegate :id, :type, :url, :preview_url, :remote_url,
+             :preview_remote_url, :text_url, :meta, :blurhash,
+             :not_processed?, :needs_redownload?, :local?,
+             :file, :thumbnail, :thumbnail_remote_url,
+             :shortcode, to: :media_attachment
   end
 
   rate_limit by: :account, family: :statuses