[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 classNames from 'classnames'; | ||||||
| import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state'; | import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state'; | ||||||
| import { decode } from 'blurhash'; | import { decode } from 'blurhash'; | ||||||
|  | import { debounce } from 'lodash'; | ||||||
| 
 | 
 | ||||||
| const messages = defineMessages({ | const messages = defineMessages({ | ||||||
|   hidden: { |   hidden: { | ||||||
|  | @ -289,6 +290,14 @@ class MediaGallery extends React.PureComponent { | ||||||
|     width: this.props.defaultWidth, |     width: this.props.defaultWidth, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   componentDidMount () { | ||||||
|  |     window.addEventListener('resize', this.handleResize, { passive: true }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   componentWillUnmount () { | ||||||
|  |     window.removeEventListener('resize', this.handleResize); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   componentWillReceiveProps (nextProps) { |   componentWillReceiveProps (nextProps) { | ||||||
|     if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) { |     if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) { | ||||||
|       this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' }); |       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 = () => { |   handleOpen = () => { | ||||||
|     if (this.props.onToggleVisibility) { |     if (this.props.onToggleVisibility) { | ||||||
|       this.props.onToggleVisibility(); |       this.props.onToggleVisibility(); | ||||||
|  | @ -319,11 +336,23 @@ class MediaGallery extends React.PureComponent { | ||||||
| 
 | 
 | ||||||
|   handleRef = (node) => { |   handleRef = (node) => { | ||||||
|     this.node = 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({ |       this.setState({ | ||||||
|         width: node.offsetWidth, |         width: width, | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ import classNames from 'classnames'; | ||||||
| import { throttle } from 'lodash'; | import { throttle } from 'lodash'; | ||||||
| import { encode, decode } from 'blurhash'; | import { encode, decode } from 'blurhash'; | ||||||
| import { getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video'; | import { getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video'; | ||||||
|  | import { debounce } from 'lodash'; | ||||||
| 
 | 
 | ||||||
| const digitCharacters = [ | const digitCharacters = [ | ||||||
|   '0', |   '0', | ||||||
|  | @ -172,18 +173,22 @@ class Audio extends React.PureComponent { | ||||||
|   setPlayerRef = c => { |   setPlayerRef = c => { | ||||||
|     this.player = c; |     this.player = c; | ||||||
| 
 | 
 | ||||||
|     if (c) { |     if (this.player) { | ||||||
|       const width  = c.offsetWidth; |       this._setDimensions(); | ||||||
|       const height = width / (16/9); |  | ||||||
| 
 |  | ||||||
|       if (this.props.cacheWidth) { |  | ||||||
|         this.props.cacheWidth(width); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       this.setState({ width, height }); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   _setDimensions () { | ||||||
|  |     const width  = this.player.offsetWidth; | ||||||
|  |     const height = width / (16/9); | ||||||
|  | 
 | ||||||
|  |     if (this.props.cacheWidth) { | ||||||
|  |       this.props.cacheWidth(width); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.setState({ width, height }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   setSeekRef = c => { |   setSeekRef = c => { | ||||||
|     this.seek = c; |     this.seek = c; | ||||||
|   } |   } | ||||||
|  | @ -213,6 +218,8 @@ class Audio extends React.PureComponent { | ||||||
|   } |   } | ||||||
|   |   | ||||||
|   componentDidMount () { |   componentDidMount () { | ||||||
|  |     window.addEventListener('resize', this.handleResize, { passive: true }); | ||||||
|  | 
 | ||||||
|     const img = new Image(); |     const img = new Image(); | ||||||
|     img.crossOrigin = 'anonymous'; |     img.crossOrigin = 'anonymous'; | ||||||
|     img.onload = () => this.handlePosterLoad(img); |     img.onload = () => this.handlePosterLoad(img); | ||||||
|  | @ -239,6 +246,10 @@ class Audio extends React.PureComponent { | ||||||
|     this._draw(); |     this._draw(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   componentWillUnmount () { | ||||||
|  |     window.removeEventListener('resize', this.handleResize); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   togglePlay = () => { |   togglePlay = () => { | ||||||
|     if (this.state.paused) { |     if (this.state.paused) { | ||||||
|       this.setState({ paused: false }, () => this.audio.play()); |       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 = () => { |   handlePlay = () => { | ||||||
|     this.setState({ paused: false }); |     this.setState({ paused: false }); | ||||||
| 
 | 
 | ||||||
|  | @ -545,14 +564,13 @@ class Audio extends React.PureComponent { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   _drawTick (x1, y1, x2, y2) { |   _drawTick (x1, y1, x2, y2) { | ||||||
|     const radius = this._getRadius(); |     const cx = this._getCX(); | ||||||
|     const cx = parseInt(this.state.width / 2); |     const cy = this._getCY(); | ||||||
|     const cy = parseInt(radius + (PADDING * this._getScaleCoefficient())); |  | ||||||
| 
 | 
 | ||||||
|     const dx1 = parseInt(cx + x1); |     const dx1 = Math.ceil(cx + x1); | ||||||
|     const dy1 = parseInt(cy + y1); |     const dy1 = Math.ceil(cy + y1); | ||||||
|     const dx2 = parseInt(cx + x2); |     const dx2 = Math.ceil(cx + x2); | ||||||
|     const dy2 = parseInt(cy + y2); |     const dy2 = Math.ceil(cy + y2); | ||||||
| 
 | 
 | ||||||
|     const gradient = this.canvasContext.createLinearGradient(dx1, dy1, dx2, dy2); |     const gradient = this.canvasContext.createLinearGradient(dx1, dy1, dx2, dy2); | ||||||
| 
 | 
 | ||||||
|  | @ -571,6 +589,14 @@ class Audio extends React.PureComponent { | ||||||
|     this.canvasContext.stroke(); |     this.canvasContext.stroke(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   _getCX() { | ||||||
|  |     return Math.floor(this.state.width / 2); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _getCY() { | ||||||
|  |     return Math.floor(this._getRadius() + (PADDING * this._getScaleCoefficient())); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   _getColor () { |   _getColor () { | ||||||
|     return `rgb(${this.state.color.r}, ${this.state.color.g}, ${this.state.color.b})`; |     return `rgb(${this.state.color.r}, ${this.state.color.g}, ${this.state.color.b})`; | ||||||
|   } |   } | ||||||
|  | @ -619,7 +645,7 @@ class Audio extends React.PureComponent { | ||||||
|           alt='' |           alt='' | ||||||
|           width={(this._getRadius() - TICK_SIZE) * 2} |           width={(this._getRadius() - TICK_SIZE) * 2} | ||||||
|           height={(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}> |         <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 Icon from 'flavours/glitch/components/icon'; | ||||||
| import { useBlurhash } from 'flavours/glitch/util/initial_state'; | import { useBlurhash } from 'flavours/glitch/util/initial_state'; | ||||||
| import { decode } from 'blurhash'; | import { decode } from 'blurhash'; | ||||||
|  | import { debounce } from 'lodash'; | ||||||
| 
 | 
 | ||||||
| const getHostname = url => { | const getHostname = url => { | ||||||
|   const parser = document.createElement('a'); |   const parser = document.createElement('a'); | ||||||
|  | @ -83,13 +84,20 @@ export default class Card extends React.PureComponent { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   componentDidMount () { |   componentDidMount () { | ||||||
|  |     window.addEventListener('resize', this.handleResize, { passive: true }); | ||||||
|  | 
 | ||||||
|     if (this.props.card && this.props.card.get('blurhash')) { |     if (this.props.card && this.props.card.get('blurhash')) { | ||||||
|       this._decode(); |       this._decode(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   componentWillUnmount () { | ||||||
|  |     window.removeEventListener('resize', this.handleResize); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   componentDidUpdate (prevProps) { |   componentDidUpdate (prevProps) { | ||||||
|     const { card } = this.props; |     const { card } = this.props; | ||||||
|  | 
 | ||||||
|     if (card.get('blurhash') && (!prevProps.card || prevProps.card.get('blurhash') !== card.get('blurhash'))) { |     if (card.get('blurhash') && (!prevProps.card || prevProps.card.get('blurhash') !== card.get('blurhash'))) { | ||||||
|       this._decode(); |       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 = () => { |   handlePhotoClick = () => { | ||||||
|     const { card, onOpenMedia } = this.props; |     const { card, onOpenMedia } = this.props; | ||||||
| 
 | 
 | ||||||
|  | @ -141,9 +167,10 @@ export default class Card extends React.PureComponent { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   setRef = c => { |   setRef = c => { | ||||||
|     if (c) { |     this.node = c; | ||||||
|       if (this.props.cacheWidth) this.props.cacheWidth(c.offsetWidth); | 
 | ||||||
|       this.setState({ width: c.offsetWidth }); |     if (this.node) { | ||||||
|  |       this._setDimensions(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import React from 'react'; | ||||||
| import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||||
| import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; | import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; | ||||||
| import { fromJS, is } from 'immutable'; | import { fromJS, is } from 'immutable'; | ||||||
| import { throttle } from 'lodash'; | import { throttle, debounce } from 'lodash'; | ||||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||||
| import { isFullscreen, requestFullscreen, exitFullscreen } from 'flavours/glitch/util/fullscreen'; | import { isFullscreen, requestFullscreen, exitFullscreen } from 'flavours/glitch/util/fullscreen'; | ||||||
| import { displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state'; | import { displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state'; | ||||||
|  | @ -144,10 +144,21 @@ class Video extends React.PureComponent { | ||||||
|   setPlayerRef = c => { |   setPlayerRef = c => { | ||||||
|     this.player = c; |     this.player = c; | ||||||
| 
 | 
 | ||||||
|     if (c && c.offsetWidth && c.offsetWidth != this.state.containerWidth) { |     if (this.player) { | ||||||
|       if (this.props.cacheWidth) this.props.cacheWidth(this.player.offsetWidth); |       this._setDimensions(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _setDimensions () { | ||||||
|  |     const width = this.player.offsetWidth; | ||||||
|  | 
 | ||||||
|  |     if (width && width != this.state.containerWidth) { | ||||||
|  |       if (this.props.cacheWidth) { | ||||||
|  |         this.props.cacheWidth(width); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       this.setState({ |       this.setState({ | ||||||
|         containerWidth: c.offsetWidth, |         containerWidth: width, | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -293,12 +304,16 @@ class Video extends React.PureComponent { | ||||||
|     document.addEventListener('mozfullscreenchange', this.handleFullscreenChange, true); |     document.addEventListener('mozfullscreenchange', this.handleFullscreenChange, true); | ||||||
|     document.addEventListener('MSFullscreenChange', this.handleFullscreenChange, true); |     document.addEventListener('MSFullscreenChange', this.handleFullscreenChange, true); | ||||||
| 
 | 
 | ||||||
|  |     window.addEventListener('resize', this.handleResize, { passive: true }); | ||||||
|  | 
 | ||||||
|     if (this.props.blurhash) { |     if (this.props.blurhash) { | ||||||
|       this._decode(); |       this._decode(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   componentWillUnmount () { |   componentWillUnmount () { | ||||||
|  |     window.removeEventListener('resize', this.handleResize); | ||||||
|  | 
 | ||||||
|     document.removeEventListener('fullscreenchange', this.handleFullscreenChange, true); |     document.removeEventListener('fullscreenchange', this.handleFullscreenChange, true); | ||||||
|     document.removeEventListener('webkitfullscreenchange', this.handleFullscreenChange, true); |     document.removeEventListener('webkitfullscreenchange', this.handleFullscreenChange, true); | ||||||
|     document.removeEventListener('mozfullscreenchange', 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 = () => { |   handleFullscreenChange = () => { | ||||||
|     this.setState({ fullscreen: isFullscreen() }); |     this.setState({ fullscreen: isFullscreen() }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -612,7 +612,7 @@ | ||||||
|     &.active { |     &.active { | ||||||
|       overflow: visible; |       overflow: visible; | ||||||
|       width: 50px; |       width: 50px; | ||||||
|       margin-right: 10px; |       margin-right: 16px; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &::before { |     &::before { | ||||||
|  | @ -649,10 +649,17 @@ | ||||||
|       left: 0; |       left: 0; | ||||||
|       margin-left: -6px; |       margin-left: -6px; | ||||||
|       transform: translate(0, -50%); |       transform: translate(0, -50%); | ||||||
|       transition: opacity .1s ease; |  | ||||||
|       background: lighten($ui-highlight-color, 8%); |       background: lighten($ui-highlight-color, 8%); | ||||||
|       box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2); |       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; |       height: 12px; | ||||||
|       top: 6px; |       top: 6px; | ||||||
|       margin-left: -6px; |       margin-left: -6px; | ||||||
|       transition: opacity .1s ease; |  | ||||||
|       background: lighten($ui-highlight-color, 8%); |       background: lighten($ui-highlight-color, 8%); | ||||||
|       box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2); |       box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2); | ||||||
|       pointer-events: none; | 
 | ||||||
|  |       .no-reduce-motion & { | ||||||
|  |         transition: opacity .1s ease; | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|       &.active { |       &.active { | ||||||
|         opacity: 1; |         opacity: 1; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue