diff --git a/app/javascript/mastodon/components/media_gallery.js b/app/javascript/mastodon/components/media_gallery.js index a31de206b4..0ec8661380 100644 --- a/app/javascript/mastodon/components/media_gallery.js +++ b/app/javascript/mastodon/components/media_gallery.js @@ -8,10 +8,10 @@ import { isIOS } from '../is_mobile'; import classNames from 'classnames'; import { autoPlayGif, cropImages, displayMedia, useBlurhash } from '../initial_state'; import { decode } from 'blurhash'; +import { debounce } from 'lodash'; const messages = defineMessages({ - toggle_visible: { id: 'media_gallery.toggle_visible', - defaultMessage: 'Hide {number, plural, one {image} other {images}}' }, + toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Hide {number, plural, one {image} other {images}}' }, }); class Item extends React.PureComponent { @@ -267,6 +267,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' }); @@ -275,6 +283,14 @@ class MediaGallery extends React.PureComponent { } } + handleResize = debounce(() => { + if (this.node) { + this._setDimensions(); + } + }, 250, { + trailing: true, + }); + handleOpen = () => { if (this.props.onToggleVisibility) { this.props.onToggleVisibility(); @@ -287,17 +303,27 @@ class MediaGallery extends React.PureComponent { this.props.onOpenMedia(this.props.media, index); } - handleRef = (node) => { - if (node) { - // offsetWidth triggers a layout, so only calculate when we need to - if (this.props.cacheWidth) this.props.cacheWidth(node.offsetWidth); + handleRef = c => { + this.node = c; - this.setState({ - width: node.offsetWidth, - }); + if (this.node) { + this._setDimensions(); } } + _setDimensions () { + const width = this.node.offsetWidth; + + // offsetWidth triggers a layout, so only calculate when we need to + if (this.props.cacheWidth) { + this.props.cacheWidth(width); + } + + this.setState({ + width: width, + }); + } + isFullSizeEligible() { const { media } = this.props; return media.size === 1 && media.getIn([0, 'meta', 'small', 'aspect']); diff --git a/app/javascript/mastodon/features/audio/index.js b/app/javascript/mastodon/features/audio/index.js index cde2357ac0..9da143c96e 100644 --- a/app/javascript/mastodon/features/audio/index.js +++ b/app/javascript/mastodon/features/audio/index.js @@ -7,6 +7,7 @@ import classNames from 'classnames'; import { throttle } from 'lodash'; import { encode, decode } from 'blurhash'; import { getPointerPosition, fileNameFromURL } from 'mastodon/features/video'; +import { debounce } from 'lodash'; const digitCharacters = [ '0', @@ -172,18 +173,22 @@ class Audio extends React.PureComponent { setPlayerRef = c => { this.player = c; - if (c) { - const width = c.offsetWidth; - const height = width / (16/9); - - if (this.props.cacheWidth) { - this.props.cacheWidth(width); - } - - this.setState({ width, height }); + if (this.player) { + this._setDimensions(); } } + _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 => { this.seek = c; } @@ -214,6 +219,7 @@ class Audio extends React.PureComponent { componentDidMount () { window.addEventListener('scroll', this.handleScroll); + window.addEventListener('resize', this.handleResize, { passive: true }); const img = new Image(); img.crossOrigin = 'anonymous'; @@ -243,6 +249,7 @@ class Audio extends React.PureComponent { componentWillUnmount () { window.removeEventListener('scroll', this.handleScroll); + window.removeEventListener('resize', this.handleResize); } togglePlay = () => { @@ -253,6 +260,14 @@ class Audio extends React.PureComponent { } } + handleResize = debounce(() => { + if (this.player) { + this._setDimensions(); + } + }, 250, { + trailing: true, + }); + handlePlay = () => { this.setState({ paused: false }); @@ -564,14 +579,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); @@ -590,6 +604,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})`; } @@ -638,7 +660,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' }} />