media_attachments.jsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import PropTypes from 'prop-types';
  2. import ImmutablePropTypes from 'react-immutable-proptypes';
  3. import ImmutablePureComponent from 'react-immutable-pure-component';
  4. import noop from 'lodash/noop';
  5. import Bundle from 'mastodon/features/ui/components/bundle';
  6. import { MediaGallery, Video, Audio } from 'mastodon/features/ui/util/async-components';
  7. export default class MediaAttachments extends ImmutablePureComponent {
  8. static propTypes = {
  9. status: ImmutablePropTypes.map.isRequired,
  10. lang: PropTypes.string,
  11. height: PropTypes.number,
  12. width: PropTypes.number,
  13. visible: PropTypes.bool,
  14. };
  15. static defaultProps = {
  16. height: 110,
  17. width: 239,
  18. };
  19. updateOnProps = [
  20. 'status',
  21. ];
  22. renderLoadingMediaGallery = () => {
  23. const { height, width } = this.props;
  24. return (
  25. <div className='media-gallery' style={{ height, width }} />
  26. );
  27. };
  28. renderLoadingVideoPlayer = () => {
  29. const { height, width } = this.props;
  30. return (
  31. <div className='video-player' style={{ height, width }} />
  32. );
  33. };
  34. renderLoadingAudioPlayer = () => {
  35. const { height, width } = this.props;
  36. return (
  37. <div className='audio-player' style={{ height, width }} />
  38. );
  39. };
  40. render () {
  41. const { status, width, height, visible } = this.props;
  42. const mediaAttachments = status.get('media_attachments');
  43. const language = status.getIn(['language', 'translation']) || status.get('language') || this.props.lang;
  44. if (mediaAttachments.size === 0) {
  45. return null;
  46. }
  47. if (mediaAttachments.getIn([0, 'type']) === 'audio') {
  48. const audio = mediaAttachments.get(0);
  49. const description = audio.getIn(['translation', 'description']) || audio.get('description');
  50. return (
  51. <Bundle fetchComponent={Audio} loading={this.renderLoadingAudioPlayer} >
  52. {Component => (
  53. <Component
  54. src={audio.get('url')}
  55. alt={description}
  56. lang={language}
  57. width={width}
  58. height={height}
  59. poster={audio.get('preview_url') || status.getIn(['account', 'avatar_static'])}
  60. backgroundColor={audio.getIn(['meta', 'colors', 'background'])}
  61. foregroundColor={audio.getIn(['meta', 'colors', 'foreground'])}
  62. accentColor={audio.getIn(['meta', 'colors', 'accent'])}
  63. duration={audio.getIn(['meta', 'original', 'duration'], 0)}
  64. />
  65. )}
  66. </Bundle>
  67. );
  68. } else if (mediaAttachments.getIn([0, 'type']) === 'video') {
  69. const video = mediaAttachments.get(0);
  70. const description = video.getIn(['translation', 'description']) || video.get('description');
  71. return (
  72. <Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer} >
  73. {Component => (
  74. <Component
  75. preview={video.get('preview_url')}
  76. frameRate={video.getIn(['meta', 'original', 'frame_rate'])}
  77. blurhash={video.get('blurhash')}
  78. src={video.get('url')}
  79. alt={description}
  80. lang={language}
  81. width={width}
  82. height={height}
  83. inline
  84. sensitive={status.get('sensitive')}
  85. visible={visible}
  86. onOpenVideo={noop}
  87. />
  88. )}
  89. </Bundle>
  90. );
  91. } else {
  92. return (
  93. <Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery} >
  94. {Component => (
  95. <Component
  96. media={mediaAttachments}
  97. lang={language}
  98. sensitive={status.get('sensitive')}
  99. defaultWidth={width}
  100. visible={visible}
  101. height={height}
  102. onOpenMedia={noop}
  103. />
  104. )}
  105. </Bundle>
  106. );
  107. }
  108. }
  109. }