@ -4,13 +4,14 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types' ;
import Video from 'mastodon/features/video' ;
import classNames from 'classnames' ;
import { defineMessages , injectIntl , FormattedMessage } from 'react-intl' ;
import { defineMessages , injectIntl } from 'react-intl' ;
import IconButton from 'mastodon/components/icon_button' ;
import ImmutablePureComponent from 'react-immutable-pure-component' ;
import ImageLoader from './image_loader' ;
import Icon from 'mastodon/components/icon' ;
import GIFV from 'mastodon/components/gifv' ;
import { disableSwiping } from 'mastodon/initial_state' ;
import Footer from 'mastodon/features/picture_in_picture/components/footer' ;
const messages = defineMessages ( {
close : { id : 'lightbox.close' , defaultMessage : 'Close' } ,
@ -20,15 +21,121 @@ const messages = defineMessages({
export const previewState = 'previewMediaModal' ;
const digitCharacters = [
'0' ,
'1' ,
'2' ,
'3' ,
'4' ,
'5' ,
'6' ,
'7' ,
'8' ,
'9' ,
'A' ,
'B' ,
'C' ,
'D' ,
'E' ,
'F' ,
'G' ,
'H' ,
'I' ,
'J' ,
'K' ,
'L' ,
'M' ,
'N' ,
'O' ,
'P' ,
'Q' ,
'R' ,
'S' ,
'T' ,
'U' ,
'V' ,
'W' ,
'X' ,
'Y' ,
'Z' ,
'a' ,
'b' ,
'c' ,
'd' ,
'e' ,
'f' ,
'g' ,
'h' ,
'i' ,
'j' ,
'k' ,
'l' ,
'm' ,
'n' ,
'o' ,
'p' ,
'q' ,
'r' ,
's' ,
't' ,
'u' ,
'v' ,
'w' ,
'x' ,
'y' ,
'z' ,
'#' ,
'$' ,
'%' ,
'*' ,
'+' ,
',' ,
'-' ,
'.' ,
':' ,
';' ,
'=' ,
'?' ,
'@' ,
'[' ,
']' ,
'^' ,
'_' ,
'{' ,
'|' ,
'}' ,
'~' ,
] ;
const decode83 = ( str ) => {
let value = 0 ;
let c , digit ;
for ( let i = 0 ; i < str . length ; i ++ ) {
c = str [ i ] ;
digit = digitCharacters . indexOf ( c ) ;
value = value * 83 + digit ;
}
return value ;
} ;
const decodeRGB = int => ( {
r : Math . max ( 0 , ( int >> 16 ) ) ,
g : Math . max ( 0 , ( int >> 8 ) & 255 ) ,
b : Math . max ( 0 , ( int & 255 ) ) ,
} ) ;
export default @ injectIntl
class MediaModal extends ImmutablePureComponent {
static propTypes = {
media : ImmutablePropTypes . list . isRequired ,
status : ImmutablePropTypes . map ,
status Id: PropTypes . string ,
index : PropTypes . number . isRequired ,
onClose : PropTypes . func . isRequired ,
intl : PropTypes . object . isRequired ,
onChangeBackgroundColor : PropTypes . func . isRequired ,
} ;
static contextTypes = {
@ -67,6 +174,7 @@ class MediaModal extends ImmutablePureComponent {
handleChangeIndex = ( e ) => {
const index = Number ( e . currentTarget . getAttribute ( 'data-index' ) ) ;
this . setState ( {
index : index % this . props . media . size ,
zoomButtonHidden : true ,
@ -100,6 +208,22 @@ class MediaModal extends ImmutablePureComponent {
this . props . onClose ( ) ;
} ) ;
}
this . _sendBackgroundColor ( ) ;
}
componentDidUpdate ( prevProps , prevState ) {
if ( prevState . index !== this . state . index ) {
this . _sendBackgroundColor ( ) ;
}
}
_sendBackgroundColor ( ) {
const { media , onChangeBackgroundColor } = this . props ;
const index = this . getIndex ( ) ;
const backgroundColor = decodeRGB ( decode83 ( media . getIn ( [ index , 'blurhash' ] ) . slice ( 2 , 6 ) ) ) ;
onChangeBackgroundColor ( backgroundColor ) ;
}
componentWillUnmount ( ) {
@ -112,6 +236,8 @@ class MediaModal extends ImmutablePureComponent {
this . context . router . history . goBack ( ) ;
}
}
this . props . onChangeBackgroundColor ( null ) ;
}
getIndex ( ) {
@ -127,30 +253,19 @@ class MediaModal extends ImmutablePureComponent {
handleStatusClick = e => {
if ( e . button === 0 && ! ( e . ctrlKey || e . metaKey ) ) {
e . preventDefault ( ) ;
this . context . router . history . push ( ` /statuses/ ${ this . props . status . get ( 'id' ) } ` ) ;
this . context . router . history . push ( ` /statuses/ ${ this . props . status Id } ` ) ;
}
}
render ( ) {
const { media , status , intl , onClose } = this . props ;
const { media , status Id , intl , onClose } = this . props ;
const { navigationHidden } = this . state ;
const index = this . getIndex ( ) ;
let pagination = [ ] ;
const leftNav = media . size > 1 && < button tabIndex = '0' className = 'media-modal__nav media-modal__nav--left' onClick = { this . handlePrevClick } aria - label = { intl . formatMessage ( messages . previous ) } > < Icon id = 'chevron-left' fixedWidth / > < / b u t t o n > ;
const rightNav = media . size > 1 && < button tabIndex = '0' className = 'media-modal__nav media-modal__nav--right' onClick = { this . handleNextClick } aria - label = { intl . formatMessage ( messages . next ) } > < Icon id = 'chevron-right' fixedWidth / > < / b u t t o n > ;
if ( media . size > 1 ) {
pagination = media . map ( ( item , i ) => {
const classes = [ 'media-modal__button' ] ;
if ( i === index ) {
classes . push ( 'media-modal__button--active' ) ;
}
return ( < li className = 'media-modal__page-dot' key = { i } > < button tabIndex = '0' className = { classes . join ( ' ' ) } onClick = { this . handleChangeIndex } data - index = { i } > { i + 1 } < / b u t t o n > < / l i > ) ;
} ) ;
}
const content = media . map ( ( image ) => {
const width = image . getIn ( [ 'meta' , 'original' , 'width' ] ) || null ;
const height = image . getIn ( [ 'meta' , 'original' , 'height' ] ) || null ;
@ -218,13 +333,19 @@ class MediaModal extends ImmutablePureComponent {
'media-modal__navigation--hidden' : navigationHidden ,
} ) ;
let pagination ;
if ( media . size > 1 ) {
pagination = media . map ( ( item , i ) => (
< button key = { i } className = { classNames ( 'media-modal__page-dot' , { active : i === index } ) } data - index = { i } onClick = { this . handleChangeIndex } >
{ i + 1 }
< / b u t t o n >
) ) ;
}
return (
< div className = 'modal-root__modal media-modal' >
< div
className = 'media-modal__closer'
role = 'presentation'
onClick = { onClose }
>
< div className = 'media-modal__closer' role = 'presentation' onClick = { onClose } >
< ReactSwipeableViews
style = { swipeableViewsStyle }
containerStyle = { containerStyle }
@ -243,15 +364,10 @@ class MediaModal extends ImmutablePureComponent {
{ leftNav }
{ rightNav }
{ status && (
< div className = { classNames ( 'media-modal__meta' , { 'media-modal__meta--shifted' : media . size > 1 } ) } >
< a href = { status . get ( 'url' ) } onClick = { this . handleStatusClick } > < Icon id = 'comments' / > < FormattedMessage id = 'lightbox.view_context' defaultMessage = 'View context' / > < / a >
< div className = 'media-modal__overlay' >
{ pagination && < ul className = 'media-modal__pagination' > { pagination } < / u l > }
{ statusId && < Footer statusId = { statusId } withOpenButton onClose = { onClose } / > }
< / d i v >
) }
< ul className = 'media-modal__pagination' >
{ pagination }
< / u l >
< / d i v >
< / d i v >
) ;