Merge pull request #426 from ThibG/glitch-soc/features/display-focal-points
Honor focal points when displaying media
This commit is contained in:
		
						commit
						40006bcd03
					
				| @ -147,6 +147,11 @@ class Item extends React.PureComponent { | ||||
|       const srcSet = hasSize ? `${originalUrl} ${originalWidth}w, ${previewUrl} ${previewWidth}w` : null; | ||||
|       const sizes  = hasSize ? `(min-width: 1025px) ${320 * (width / 100)}px, ${width}vw` : null; | ||||
| 
 | ||||
|       const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0; | ||||
|       const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0; | ||||
|       const x      = ((focusX /  2) + .5) * 100; | ||||
|       const y      = ((focusY / -2) + .5) * 100; | ||||
| 
 | ||||
|       thumbnail = ( | ||||
|         <a | ||||
|           className='media-gallery__item-thumbnail' | ||||
| @ -154,7 +159,14 @@ class Item extends React.PureComponent { | ||||
|           onClick={this.handleClick} | ||||
|           target='_blank' | ||||
|         > | ||||
|           <img className={letterbox ? 'letterbox' : null} src={previewUrl} srcSet={srcSet} sizes={sizes} alt={attachment.get('description')} title={attachment.get('description')} /> | ||||
|           <img | ||||
|             className={letterbox ? 'letterbox' : null} | ||||
|             src={previewUrl} | ||||
|             srcSet={srcSet} | ||||
|             sizes={sizes} | ||||
|             alt={attachment.get('description')} | ||||
|             title={attachment.get('description')} | ||||
|             style={{ objectPosition: `${x}% ${y}%` }} /> | ||||
|         </a> | ||||
|       ); | ||||
|     } else if (attachment.get('type') === 'gifv') { | ||||
| @ -225,30 +237,59 @@ export default class MediaGallery extends React.PureComponent { | ||||
|     this.props.onOpenMedia(this.props.media, index); | ||||
|   } | ||||
| 
 | ||||
|   handleRef = (node) => { | ||||
|     if (node && this.isStandaloneEligible()) { | ||||
|       // offsetWidth triggers a layout, so only calculate when we need to
 | ||||
|       this.setState({ | ||||
|         width: node.offsetWidth, | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   isStandaloneEligible() { | ||||
|     const { media, standalone } = this.props; | ||||
|     return standalone && media.size === 1 && media.getIn([0, 'meta', 'small', 'aspect']); | ||||
|   } | ||||
| 
 | ||||
|   render () { | ||||
|     const { | ||||
|       handleClick, | ||||
|       handleOpen, | ||||
|     } = this; | ||||
|     const { | ||||
|       fullwidth, | ||||
|       intl, | ||||
|       letterbox, | ||||
|       media, | ||||
|       sensitive, | ||||
|       standalone, | ||||
|     } = this.props; | ||||
|     const { visible } = this.state; | ||||
|     const { media, intl, sensitive, letterbox, fullwidth } = this.props; | ||||
|     const { width, visible } = this.state; | ||||
|     const size = media.take(4).size; | ||||
| 
 | ||||
|     let children; | ||||
| 
 | ||||
|     const style = {}; | ||||
| 
 | ||||
|     if (this.isStandaloneEligible() && width) { | ||||
|       style.height = width / this.props.media.getIn([0, 'meta', 'small', 'aspect']); | ||||
|     } | ||||
| 
 | ||||
|     if (!visible) { | ||||
|       let warning = <FormattedMessage {...(sensitive ? messages.warning : messages.hidden)} />; | ||||
| 
 | ||||
|       children = ( | ||||
|         <button className='media-spoiler' type='button' onClick={this.handleOpen}> | ||||
|           <span className='media-spoiler__warning'>{warning}</span> | ||||
|           <span className='media-spoiler__trigger'><FormattedMessage {...messages.toggle} /></span> | ||||
|         </button> | ||||
|       ); | ||||
|     } else { | ||||
|       if (this.isStandaloneEligible()) { | ||||
|         children = <Item standalone attachment={media.get(0)} onClick={this.handleClick} />; | ||||
|       } else { | ||||
|         children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} letterbox={letterbox} />); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     const computedClass = classNames('media-gallery', `size-${size}`, { 'full-width': fullwidth }); | ||||
| 
 | ||||
|     return ( | ||||
|       <div className={computedClass}> | ||||
|       <div className={computedClass} style={style} ref={this.handleRef}> | ||||
|         {visible ? ( | ||||
|           <div className='sensitive-info'> | ||||
|             <IconButton | ||||
|               icon='eye' | ||||
|               onClick={handleOpen} | ||||
|               onClick={this.handleOpen} | ||||
|               overlay | ||||
|               title={intl.formatMessage(messages.toggle_visible)} | ||||
|             /> | ||||
| @ -259,46 +300,8 @@ export default class MediaGallery extends React.PureComponent { | ||||
|             ) : null} | ||||
|           </div> | ||||
|         ) : null} | ||||
|         {function () { | ||||
|           switch (true) { | ||||
|           case !visible: | ||||
|             return ( | ||||
|               <button | ||||
|                 className='media-spoiler' | ||||
|                 type='button' | ||||
|                 onClick={handleOpen} | ||||
|               > | ||||
|                 <span className='media-spoiler__warning'> | ||||
|                   <FormattedMessage {...(sensitive ? messages.warning : messages.hidden)} /> | ||||
|                 </span> | ||||
|                 <span className='media-spoiler__trigger'> | ||||
|                   <FormattedMessage {...messages.toggle} /> | ||||
|                 </span> | ||||
|               </button> | ||||
|             ); | ||||
|           case standalone && media.size === 1 && !!media.getIn([0, 'meta', 'small', 'aspect']): | ||||
|             return ( | ||||
|               <Item | ||||
|                 attachment={media.get(0)} | ||||
|                 onClick={handleClick} | ||||
|                 standalone | ||||
|               /> | ||||
|             ); | ||||
|           default: | ||||
|             return media.take(4).map( | ||||
|               (attachment, i) => ( | ||||
|                 <Item | ||||
|                   attachment={attachment} | ||||
|                   index={i} | ||||
|                   key={attachment.get('id')} | ||||
|                   letterbox={letterbox} | ||||
|                   onClick={handleClick} | ||||
|                   size={size} | ||||
|                 /> | ||||
|               ) | ||||
|             ); | ||||
|           } | ||||
|         }()} | ||||
| 
 | ||||
|         {children} | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| @ -4,7 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||
| import Avatar from 'flavours/glitch/components/avatar'; | ||||
| import DisplayName from 'flavours/glitch/components/display_name'; | ||||
| import StatusContent from 'flavours/glitch/components/status_content'; | ||||
| import StatusGallery from 'flavours/glitch/components/media_gallery'; | ||||
| import MediaGallery from 'flavours/glitch/components/media_gallery'; | ||||
| import AttachmentList from 'flavours/glitch/components/attachment_list'; | ||||
| import { Link } from 'react-router-dom'; | ||||
| import { FormattedDate, FormattedNumber } from 'react-intl'; | ||||
| @ -69,7 +69,8 @@ export default class DetailedStatus extends ImmutablePureComponent { | ||||
|         mediaIcon = 'video-camera'; | ||||
|       } else { | ||||
|         media = ( | ||||
|           <StatusGallery | ||||
|           <MediaGallery | ||||
|             standalone | ||||
|             sensitive={status.get('sensitive')} | ||||
|             media={status.get('media_attachments')} | ||||
|             letterbox={settings.getIn(['media', 'letterbox'])} | ||||
|  | ||||
| @ -29,7 +29,7 @@ const formatTime = secondsNum => { | ||||
|   return (hours === '00' ? '' : `${hours}:`) + `${minutes}:${seconds}`; | ||||
| }; | ||||
| 
 | ||||
| const findElementPosition = el => { | ||||
| export const findElementPosition = el => { | ||||
|   let box; | ||||
| 
 | ||||
|   if (el.getBoundingClientRect && el.parentNode) { | ||||
| @ -60,7 +60,7 @@ const findElementPosition = el => { | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const getPointerPosition = (el, event) => { | ||||
| export const getPointerPosition = (el, event) => { | ||||
|   const position = {}; | ||||
|   const box = findElementPosition(el); | ||||
|   const boxW = el.offsetWidth; | ||||
| @ -76,7 +76,7 @@ const getPointerPosition = (el, event) => { | ||||
|     pageY = event.changedTouches[0].pageY; | ||||
|   } | ||||
| 
 | ||||
|   position.y = Math.max(0, Math.min(1, ((boxY - pageY) + boxH) / boxH)); | ||||
|   position.y = Math.max(0, Math.min(1, (pageY - boxY) / boxH)); | ||||
|   position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW)); | ||||
| 
 | ||||
|   return position; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user