about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2019-08-14 04:07:32 +0200
committerThibaut Girka <thib@sitedethib.com>2019-08-19 21:56:25 +0200
commitab019800f8862a84eab679ea5848c3df0531ddc9 (patch)
tree85334d309f0353649614b0da9b7fb167b0427a15 /app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
parentf8e7c69861e0ec3fac8d7f416c8bff7148824dc0 (diff)
[Glitch] Add media editing modal
Port 23f7afa562c49b24e979505680463bc712b11d94 to glitch-soc

Signed-off-by: Thibaut Girka <thib@sitedethib.com>
Diffstat (limited to 'app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js')
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js129
1 files changed, 105 insertions, 24 deletions
diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
index 57c92cc66..de87ba83f 100644
--- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
@@ -1,11 +1,21 @@
 import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
+import PropTypes from 'prop-types';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { connect } from 'react-redux';
-import ImageLoader from './image_loader';
 import classNames from 'classnames';
 import { changeUploadCompose } from 'flavours/glitch/actions/compose';
 import { getPointerPosition } from 'flavours/glitch/features/video';
+import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
+import IconButton from 'flavours/glitch/components/icon_button';
+import Button from 'flavours/glitch/components/button';
+import Video from 'flavours/glitch/features/video';
+
+const messages = defineMessages({
+  close: { id: 'lightbox.close', defaultMessage: 'Close' },
+  apply: { id: 'upload_modal.apply', defaultMessage: 'Apply' },
+  placeholder: { id: 'upload_modal.description_placeholder', defaultMessage: 'A quick brown fox jumps over the lazy dog' },
+});
 
 const mapStateToProps = (state, { id }) => ({
   media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id),
@@ -13,17 +23,20 @@ const mapStateToProps = (state, { id }) => ({
 
 const mapDispatchToProps = (dispatch, { id }) => ({
 
-  onSave: (x, y) => {
-    dispatch(changeUploadCompose(id, { focus: `${x.toFixed(2)},${y.toFixed(2)}` }));
+  onSave: (description, x, y) => {
+    dispatch(changeUploadCompose(id, { description, focus: `${x.toFixed(2)},${y.toFixed(2)}` }));
   },
 
 });
 
-@connect(mapStateToProps, mapDispatchToProps)
-export default class FocalPointModal extends ImmutablePureComponent {
+export default @connect(mapStateToProps, mapDispatchToProps)
+@injectIntl
+class FocalPointModal extends ImmutablePureComponent {
 
   static propTypes = {
     media: ImmutablePropTypes.map.isRequired,
+    onClose: PropTypes.func.isRequired,
+    intl: PropTypes.object.isRequired,
   };
 
   state = {
@@ -32,6 +45,8 @@ export default class FocalPointModal extends ImmutablePureComponent {
     focusX: 0,
     focusY: 0,
     dragging: false,
+    description: '',
+    dirty: false,
   };
 
   componentWillMount () {
@@ -66,7 +81,6 @@ export default class FocalPointModal extends ImmutablePureComponent {
     document.removeEventListener('mouseup', this.handleMouseUp);
 
     this.setState({ dragging: false });
-    this.props.onSave(this.state.focusX, this.state.focusY);
   }
 
   updatePosition = e => {
@@ -74,46 +88,113 @@ export default class FocalPointModal extends ImmutablePureComponent {
     const focusX   = (x - .5) *  2;
     const focusY   = (y - .5) * -2;
 
-    this.setState({ x, y, focusX, focusY });
+    this.setState({ x, y, focusX, focusY, dirty: true });
   }
 
   updatePositionFromMedia = media => {
-    const focusX = media.getIn(['meta', 'focus', 'x']);
-    const focusY = media.getIn(['meta', 'focus', 'y']);
+    const focusX      = media.getIn(['meta', 'focus', 'x']);
+    const focusY      = media.getIn(['meta', 'focus', 'y']);
+    const description = media.get('description') || '';
 
     if (focusX && focusY) {
       const x = (focusX /  2) + .5;
       const y = (focusY / -2) + .5;
 
-      this.setState({ x, y, focusX, focusY });
+      this.setState({
+        x,
+        y,
+        focusX,
+        focusY,
+        description,
+        dirty: false,
+      });
     } else {
-      this.setState({ x: 0.5, y: 0.5, focusX: 0, focusY: 0 });
+      this.setState({
+        x: 0.5,
+        y: 0.5,
+        focusX: 0,
+        focusY: 0,
+        description,
+        dirty: false,
+      });
     }
   }
 
+  handleChange = e => {
+    this.setState({ description: e.target.value, dirty: true });
+  }
+
+  handleSubmit = () => {
+    this.props.onSave(this.state.description, this.state.focusX, this.state.focusY);
+    this.props.onClose();
+  }
+
   setRef = c => {
     this.node = c;
   }
 
   render () {
-    const { media } = this.props;
-    const { x, y, dragging } = this.state;
+    const { media, intl, onClose } = this.props;
+    const { x, y, dragging, description, dirty } = this.state;
 
     const width  = media.getIn(['meta', 'original', 'width']) || null;
     const height = media.getIn(['meta', 'original', 'height']) || null;
+    const focals = ['image', 'gifv'].includes(media.get('type'));
+
+    const previewRatio  = 16/9;
+    const previewWidth  = 200;
+    const previewHeight = previewWidth / previewRatio;
 
     return (
-      <div className='modal-root__modal video-modal focal-point-modal'>
-        <div className={classNames('focal-point', { dragging })} ref={this.setRef}>
-          <ImageLoader
-            previewSrc={media.get('preview_url')}
-            src={media.get('url')}
-            width={width}
-            height={height}
-          />
-
-          <div className='focal-point__reticle' style={{ top: `${y * 100}%`, left: `${x * 100}%` }} />
-          <div className='focal-point__overlay' onMouseDown={this.handleMouseDown} />
+      <div className='modal-root__modal report-modal' style={{ maxWidth: 960 }}>
+        <div className='report-modal__target'>
+          <IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={16} />
+          <FormattedMessage id='upload_modal.edit_media' defaultMessage='Edit media' />
+        </div>
+
+        <div className='report-modal__container'>
+          <div className='report-modal__comment'>
+            {focals && <p><FormattedMessage id='upload_modal.hint' defaultMessage='Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.' /></p>}
+
+            <label className='setting-text-label' htmlFor='upload-modal__description'><FormattedMessage id='upload_form.description' defaultMessage='Describe for the visually impaired' /></label>
+
+            <textarea
+              id='upload-modal__description'
+              className='setting-text light'
+              value={description}
+              onChange={this.handleChange}
+              autoFocus
+            />
+
+            <Button disabled={!dirty} text={intl.formatMessage(messages.apply)} onClick={this.handleSubmit} />
+          </div>
+
+          <div className='report-modal__statuses'>
+            {focals && (
+              <div className={classNames('focal-point', { dragging })} ref={this.setRef}>
+                {media.get('type') === 'image' && <img src={media.get('url')} width={width} height={height} alt='' />}
+                {media.get('type') === 'gifv' && <video src={media.get('url')} width={width} height={height} loop muted autoPlay />}
+
+                <div className='focal-point__preview'>
+                  <strong><FormattedMessage id='upload_modal.preview_label' defaultMessage='Preview ({ratio})' values={{ ratio: '16:9' }} /></strong>
+                  <div style={{ width: previewWidth, height: previewHeight, backgroundImage: `url(${media.get('preview_url')})`, backgroundSize: 'cover', backgroundPosition: `${x * 100}% ${y * 100}%` }} />
+                </div>
+
+                <div className='focal-point__reticle' style={{ top: `${y * 100}%`, left: `${x * 100}%` }} />
+                <div className='focal-point__overlay' onMouseDown={this.handleMouseDown} />
+              </div>
+            )}
+
+            {['audio', 'video'].includes(media.get('type')) && (
+              <Video
+                preview={media.get('preview_url')}
+                blurhash={media.get('blurhash')}
+                src={media.get('url')}
+                detailed
+                editable
+              />
+            )}
+          </div>
         </div>
       </div>
     );