[Glitch] Fix audio/video/images/cards not reacting to window resizes in web UI
Port bb9ca8a587 to glitch-soc
Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>
Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>
Signed-off-by: Thibaut Girka <thib@sitedethib.com>
			
			
This commit is contained in:
		
							parent
							
								
									1c58420831
								
							
						
					
					
						commit
						06309129be
					
				
					 5 changed files with 146 additions and 32 deletions
				
			
		|  | @ -8,6 +8,7 @@ import { isIOS } from 'flavours/glitch/util/is_mobile'; | |||
| import classNames from 'classnames'; | ||||
| import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state'; | ||||
| import { decode } from 'blurhash'; | ||||
| import { debounce } from 'lodash'; | ||||
| 
 | ||||
| const messages = defineMessages({ | ||||
|   hidden: { | ||||
|  | @ -289,6 +290,14 @@ class MediaGallery extends React.PureComponent { | |||
|     width: this.props.defaultWidth, | ||||
|   }; | ||||
| 
 | ||||
|   componentDidMount () { | ||||
|     window.addEventListener('resize', this.handleResize, { passive: true }); | ||||
|   } | ||||
| 
 | ||||
|   componentWillUnmount () { | ||||
|     window.removeEventListener('resize', this.handleResize); | ||||
|   } | ||||
| 
 | ||||
|   componentWillReceiveProps (nextProps) { | ||||
|     if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) { | ||||
|       this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' }); | ||||
|  | @ -305,6 +314,14 @@ class MediaGallery extends React.PureComponent { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   handleResize = debounce(() => { | ||||
|     if (this.node) { | ||||
|       this._setDimensions(); | ||||
|     } | ||||
|   }, 250, { | ||||
|     trailing: true, | ||||
|   }); | ||||
| 
 | ||||
|   handleOpen = () => { | ||||
|     if (this.props.onToggleVisibility) { | ||||
|       this.props.onToggleVisibility(); | ||||
|  | @ -319,11 +336,23 @@ class MediaGallery extends React.PureComponent { | |||
| 
 | ||||
|   handleRef = (node) => { | ||||
|     this.node = node; | ||||
|     if (node && node.offsetWidth && node.offsetWidth != this.state.width) { | ||||
|       if (this.props.cacheWidth) this.props.cacheWidth(node.offsetWidth); | ||||
| 
 | ||||
|     if (this.node) { | ||||
|       this._setDimensions(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   _setDimensions () { | ||||
|     const width = this.node.offsetWidth; | ||||
|   | ||||
|     if (width && width != this.state.width) { | ||||
|       // offsetWidth triggers a layout, so only calculate when we need to
 | ||||
|       if (this.props.cacheWidth) { | ||||
|         this.props.cacheWidth(width); | ||||
|       } | ||||
| 
 | ||||
|       this.setState({ | ||||
|         width: node.offsetWidth, | ||||
|         width: width, | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import classNames from 'classnames'; | |||
| import { throttle } from 'lodash'; | ||||
| import { encode, decode } from 'blurhash'; | ||||
| import { getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video'; | ||||
| import { debounce } from 'lodash'; | ||||
| 
 | ||||
| const digitCharacters = [ | ||||
|   '0', | ||||
|  | @ -172,8 +173,13 @@ class Audio extends React.PureComponent { | |||
|   setPlayerRef = c => { | ||||
|     this.player = c; | ||||
| 
 | ||||
|     if (c) { | ||||
|       const width  = c.offsetWidth; | ||||
|     if (this.player) { | ||||
|       this._setDimensions(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   _setDimensions () { | ||||
|     const width  = this.player.offsetWidth; | ||||
|     const height = width / (16/9); | ||||
| 
 | ||||
|     if (this.props.cacheWidth) { | ||||
|  | @ -182,7 +188,6 @@ class Audio extends React.PureComponent { | |||
| 
 | ||||
|     this.setState({ width, height }); | ||||
|   } | ||||
|   } | ||||
| 
 | ||||
|   setSeekRef = c => { | ||||
|     this.seek = c; | ||||
|  | @ -213,6 +218,8 @@ class Audio extends React.PureComponent { | |||
|   } | ||||
|   | ||||
|   componentDidMount () { | ||||
|     window.addEventListener('resize', this.handleResize, { passive: true }); | ||||
| 
 | ||||
|     const img = new Image(); | ||||
|     img.crossOrigin = 'anonymous'; | ||||
|     img.onload = () => this.handlePosterLoad(img); | ||||
|  | @ -239,6 +246,10 @@ class Audio extends React.PureComponent { | |||
|     this._draw(); | ||||
|   } | ||||
| 
 | ||||
|   componentWillUnmount () { | ||||
|     window.removeEventListener('resize', this.handleResize); | ||||
|   } | ||||
| 
 | ||||
|   togglePlay = () => { | ||||
|     if (this.state.paused) { | ||||
|       this.setState({ paused: false }, () => this.audio.play()); | ||||
|  | @ -247,6 +258,14 @@ class Audio extends React.PureComponent { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   handleResize = debounce(() => { | ||||
|     if (this.player) { | ||||
|       this._setDimensions(); | ||||
|     } | ||||
|   }, 250, { | ||||
|     trailing: true, | ||||
|   }); | ||||
| 
 | ||||
|   handlePlay = () => { | ||||
|     this.setState({ paused: false }); | ||||
| 
 | ||||
|  | @ -545,14 +564,13 @@ class Audio extends React.PureComponent { | |||
|   } | ||||
| 
 | ||||
|   _drawTick (x1, y1, x2, y2) { | ||||
|     const radius = this._getRadius(); | ||||
|     const cx = parseInt(this.state.width / 2); | ||||
|     const cy = parseInt(radius + (PADDING * this._getScaleCoefficient())); | ||||
|     const cx = this._getCX(); | ||||
|     const cy = this._getCY(); | ||||
| 
 | ||||
|     const dx1 = parseInt(cx + x1); | ||||
|     const dy1 = parseInt(cy + y1); | ||||
|     const dx2 = parseInt(cx + x2); | ||||
|     const dy2 = parseInt(cy + y2); | ||||
|     const dx1 = Math.ceil(cx + x1); | ||||
|     const dy1 = Math.ceil(cy + y1); | ||||
|     const dx2 = Math.ceil(cx + x2); | ||||
|     const dy2 = Math.ceil(cy + y2); | ||||
| 
 | ||||
|     const gradient = this.canvasContext.createLinearGradient(dx1, dy1, dx2, dy2); | ||||
| 
 | ||||
|  | @ -571,6 +589,14 @@ class Audio extends React.PureComponent { | |||
|     this.canvasContext.stroke(); | ||||
|   } | ||||
| 
 | ||||
|   _getCX() { | ||||
|     return Math.floor(this.state.width / 2); | ||||
|   } | ||||
| 
 | ||||
|   _getCY() { | ||||
|     return Math.floor(this._getRadius() + (PADDING * this._getScaleCoefficient())); | ||||
|   } | ||||
| 
 | ||||
|   _getColor () { | ||||
|     return `rgb(${this.state.color.r}, ${this.state.color.g}, ${this.state.color.b})`; | ||||
|   } | ||||
|  | @ -619,7 +645,7 @@ class Audio extends React.PureComponent { | |||
|           alt='' | ||||
|           width={(this._getRadius() - TICK_SIZE) * 2} | ||||
|           height={(this._getRadius() - TICK_SIZE) * 2} | ||||
|           style={{ position: 'absolute', left: parseInt(this.state.width / 2), top: parseInt(this._getRadius() + (PADDING * this._getScaleCoefficient())), transform: 'translate(-50%, -50%)', borderRadius: '50%', pointerEvents: 'none' }} | ||||
|           style={{ position: 'absolute', left: this._getCX(), top: this._getCY(), transform: 'translate(-50%, -50%)', borderRadius: '50%', pointerEvents: 'none' }} | ||||
|         /> | ||||
| 
 | ||||
|         <div className='video-player__seek' onMouseDown={this.handleMouseDown} ref={this.setSeekRef}> | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ import { decode as decodeIDNA } from 'flavours/glitch/util/idna'; | |||
| import Icon from 'flavours/glitch/components/icon'; | ||||
| import { useBlurhash } from 'flavours/glitch/util/initial_state'; | ||||
| import { decode } from 'blurhash'; | ||||
| import { debounce } from 'lodash'; | ||||
| 
 | ||||
| const getHostname = url => { | ||||
|   const parser = document.createElement('a'); | ||||
|  | @ -83,13 +84,20 @@ export default class Card extends React.PureComponent { | |||
|   } | ||||
| 
 | ||||
|   componentDidMount () { | ||||
|     window.addEventListener('resize', this.handleResize, { passive: true }); | ||||
| 
 | ||||
|     if (this.props.card && this.props.card.get('blurhash')) { | ||||
|       this._decode(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentWillUnmount () { | ||||
|     window.removeEventListener('resize', this.handleResize); | ||||
|   } | ||||
| 
 | ||||
|   componentDidUpdate (prevProps) { | ||||
|     const { card } = this.props; | ||||
| 
 | ||||
|     if (card.get('blurhash') && (!prevProps.card || prevProps.card.get('blurhash') !== card.get('blurhash'))) { | ||||
|       this._decode(); | ||||
|     } | ||||
|  | @ -109,6 +117,24 @@ export default class Card extends React.PureComponent { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   _setDimensions () { | ||||
|     const width = this.node.offsetWidth; | ||||
| 
 | ||||
|     if (this.props.cacheWidth) { | ||||
|       this.props.cacheWidth(width); | ||||
|     } | ||||
| 
 | ||||
|     this.setState({ width }); | ||||
|   } | ||||
| 
 | ||||
|   handleResize = debounce(() => { | ||||
|     if (this.node) { | ||||
|       this._setDimensions(); | ||||
|     } | ||||
|   }, 250, { | ||||
|     trailing: true, | ||||
|   }); | ||||
| 
 | ||||
|   handlePhotoClick = () => { | ||||
|     const { card, onOpenMedia } = this.props; | ||||
| 
 | ||||
|  | @ -141,9 +167,10 @@ export default class Card extends React.PureComponent { | |||
|   } | ||||
| 
 | ||||
|   setRef = c => { | ||||
|     if (c) { | ||||
|       if (this.props.cacheWidth) this.props.cacheWidth(c.offsetWidth); | ||||
|       this.setState({ width: c.offsetWidth }); | ||||
|     this.node = c; | ||||
| 
 | ||||
|     if (this.node) { | ||||
|       this._setDimensions(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ import React from 'react'; | |||
| import PropTypes from 'prop-types'; | ||||
| import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; | ||||
| import { fromJS, is } from 'immutable'; | ||||
| import { throttle } from 'lodash'; | ||||
| import { throttle, debounce } from 'lodash'; | ||||
| import classNames from 'classnames'; | ||||
| import { isFullscreen, requestFullscreen, exitFullscreen } from 'flavours/glitch/util/fullscreen'; | ||||
| import { displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state'; | ||||
|  | @ -144,10 +144,21 @@ class Video extends React.PureComponent { | |||
|   setPlayerRef = c => { | ||||
|     this.player = c; | ||||
| 
 | ||||
|     if (c && c.offsetWidth && c.offsetWidth != this.state.containerWidth) { | ||||
|       if (this.props.cacheWidth) this.props.cacheWidth(this.player.offsetWidth); | ||||
|     if (this.player) { | ||||
|       this._setDimensions(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   _setDimensions () { | ||||
|     const width = this.player.offsetWidth; | ||||
| 
 | ||||
|     if (width && width != this.state.containerWidth) { | ||||
|       if (this.props.cacheWidth) { | ||||
|         this.props.cacheWidth(width); | ||||
|       } | ||||
| 
 | ||||
|       this.setState({ | ||||
|         containerWidth: c.offsetWidth, | ||||
|         containerWidth: width, | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
|  | @ -293,12 +304,16 @@ class Video extends React.PureComponent { | |||
|     document.addEventListener('mozfullscreenchange', this.handleFullscreenChange, true); | ||||
|     document.addEventListener('MSFullscreenChange', this.handleFullscreenChange, true); | ||||
| 
 | ||||
|     window.addEventListener('resize', this.handleResize, { passive: true }); | ||||
| 
 | ||||
|     if (this.props.blurhash) { | ||||
|       this._decode(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentWillUnmount () { | ||||
|     window.removeEventListener('resize', this.handleResize); | ||||
| 
 | ||||
|     document.removeEventListener('fullscreenchange', this.handleFullscreenChange, true); | ||||
|     document.removeEventListener('webkitfullscreenchange', this.handleFullscreenChange, true); | ||||
|     document.removeEventListener('mozfullscreenchange', this.handleFullscreenChange, true); | ||||
|  | @ -334,6 +349,14 @@ class Video extends React.PureComponent { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   handleResize = debounce(() => { | ||||
|     if (this.player) { | ||||
|       this._setDimensions(); | ||||
|     } | ||||
|   }, 250, { | ||||
|     trailing: true, | ||||
|   }); | ||||
| 
 | ||||
|   handleFullscreenChange = () => { | ||||
|     this.setState({ fullscreen: isFullscreen() }); | ||||
|   } | ||||
|  |  | |||
|  | @ -612,7 +612,7 @@ | |||
|     &.active { | ||||
|       overflow: visible; | ||||
|       width: 50px; | ||||
|       margin-right: 10px; | ||||
|       margin-right: 16px; | ||||
|     } | ||||
| 
 | ||||
|     &::before { | ||||
|  | @ -649,10 +649,17 @@ | |||
|       left: 0; | ||||
|       margin-left: -6px; | ||||
|       transform: translate(0, -50%); | ||||
|       transition: opacity .1s ease; | ||||
|       background: lighten($ui-highlight-color, 8%); | ||||
|       box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2); | ||||
|       pointer-events: none; | ||||
|       opacity: 0; | ||||
| 
 | ||||
|       .no-reduce-motion & { | ||||
|         transition: opacity 100ms linear; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     &.active &__handle { | ||||
|       opacity: 1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -712,10 +719,12 @@ | |||
|       height: 12px; | ||||
|       top: 6px; | ||||
|       margin-left: -6px; | ||||
|       transition: opacity .1s ease; | ||||
|       background: lighten($ui-highlight-color, 8%); | ||||
|       box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2); | ||||
|       pointer-events: none; | ||||
| 
 | ||||
|       .no-reduce-motion & { | ||||
|         transition: opacity .1s ease; | ||||
|       } | ||||
| 
 | ||||
|       &.active { | ||||
|         opacity: 1; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue