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 {
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' });
}
}
+ handleResize = debounce(() => {
+ if (this.node) {
+ this._setDimensions();
+ }
+ }, 250, {
+ trailing: true,
+ });
+
handleOpen = () => {
if (this.props.onToggleVisibility) {
this.props.onToggleVisibility();
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;
+
+ if (this.node) {
+ this._setDimensions();
+ }
+ }
+
+ _setDimensions () {
+ const width = this.node.offsetWidth;
- this.setState({
- width: 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() {
import { throttle } from 'lodash';
import { encode, decode } from 'blurhash';
import { getPointerPosition, fileNameFromURL } from 'mastodon/features/video';
+import { debounce } from 'lodash';
const digitCharacters = [
'0',
setPlayerRef = c => {
this.player = c;
- if (c) {
- const width = c.offsetWidth;
- const height = width / (16/9);
+ if (this.player) {
+ this._setDimensions();
+ }
+ }
- if (this.props.cacheWidth) {
- this.props.cacheWidth(width);
- }
+ _setDimensions () {
+ const width = this.player.offsetWidth;
+ const height = width / (16/9);
- this.setState({ width, height });
+ if (this.props.cacheWidth) {
+ this.props.cacheWidth(width);
}
+
+ this.setState({ width, height });
}
setSeekRef = c => {
componentDidMount () {
window.addEventListener('scroll', this.handleScroll);
+ window.addEventListener('resize', this.handleResize, { passive: true });
const img = new Image();
img.crossOrigin = 'anonymous';
componentWillUnmount () {
window.removeEventListener('scroll', this.handleScroll);
+ window.removeEventListener('resize', this.handleResize);
}
togglePlay = () => {
}
}
+ handleResize = debounce(() => {
+ if (this.player) {
+ this._setDimensions();
+ }
+ }, 250, {
+ trailing: true,
+ });
+
handlePlay = () => {
this.setState({ paused: false });
}
_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);
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})`;
}
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}>
import classNames from 'classnames';
import { useBlurhash } from 'mastodon/initial_state';
import { decode } from 'blurhash';
+import { debounce } from 'lodash';
const IDNA_PREFIX = 'xn--';
}
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();
}
}
}
+ _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;
}
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();
}
}
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 '../ui/util/fullscreen';
import { displayMedia, useBlurhash } from '../../initial_state';
setPlayerRef = c => {
this.player = c;
- if (c) {
- if (this.props.cacheWidth) this.props.cacheWidth(this.player.offsetWidth);
+ if (this.player) {
+ this._setDimensions();
+ }
+ }
- this.setState({
- containerWidth: c.offsetWidth,
- });
+ _setDimensions () {
+ const width = this.player.offsetWidth;
+
+ if (this.props.cacheWidth) {
+ this.props.cacheWidth(width);
}
+
+ this.setState({
+ containerWidth: width,
+ });
}
setVideoRef = c => {
document.addEventListener('MSFullscreenChange', this.handleFullscreenChange, true);
window.addEventListener('scroll', this.handleScroll);
+ window.addEventListener('resize', this.handleResize, { passive: true });
if (this.props.blurhash) {
this._decode();
componentWillUnmount () {
window.removeEventListener('scroll', this.handleScroll);
+ window.removeEventListener('resize', this.handleResize);
document.removeEventListener('fullscreenchange', this.handleFullscreenChange, true);
document.removeEventListener('webkitfullscreenchange', this.handleFullscreenChange, true);
}
}
+ handleResize = debounce(() => {
+ if (this.player) {
+ this._setDimensions();
+ }
+ }, 250, {
+ trailing: true,
+ });
+
handleScroll = throttle(() => {
if (!this.video) {
return;
&.active {
overflow: visible;
width: 50px;
- margin-right: 10px;
+ margin-right: 16px;
}
&::before {
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;
}
}
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;