Merge branch 'pause-gif' of git://github.com/patf/mastodon into patf-pause-gif
This commit is contained in:
		
						commit
						57d784f1e4
					
				| @ -78,7 +78,8 @@ const Item = React.createClass({ | |||||||
|     attachment: ImmutablePropTypes.map.isRequired, |     attachment: ImmutablePropTypes.map.isRequired, | ||||||
|     index: React.PropTypes.number.isRequired, |     index: React.PropTypes.number.isRequired, | ||||||
|     size: React.PropTypes.number.isRequired, |     size: React.PropTypes.number.isRequired, | ||||||
|     onClick: React.PropTypes.func.isRequired |     onClick: React.PropTypes.func.isRequired, | ||||||
|  |     autoPlayGif: React.PropTypes.bool.isRequired | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   mixins: [PureRenderMixin], |   mixins: [PureRenderMixin], | ||||||
| @ -158,16 +159,24 @@ const Item = React.createClass({ | |||||||
|         /> |         /> | ||||||
|       ); |       ); | ||||||
|     } else if (attachment.get('type') === 'gifv') { |     } else if (attachment.get('type') === 'gifv') { | ||||||
|       thumbnail = ( |       if (isIOS() || !this.props.autoPlayGif) { | ||||||
|         <video |         return ( | ||||||
|           src={attachment.get('url')} |           <div  key={attachment.get('id')} style={{ ...itemStyle, background: `url(${attachment.get('preview_url')}) no-repeat center`, left: left, top: top, right: right, bottom: bottom, width: `${width}%`, height: `${height}%` }} onClick={this.handleClick}> | ||||||
|           onClick={this.handleClick} |             <div style={{ position: 'absolute', top: '50%', left: '50%', fontSize: '36px', transform: 'translate(-50%, -50%)', padding: '5px', borderRadius: '100px', color: 'rgba(255, 255, 255, 0.8)' }}><i className='fa fa-play' /></div> | ||||||
|           autoPlay={!isIOS()} |           </div> | ||||||
|           loop={true} |         ); | ||||||
|           muted={true} |       } else { | ||||||
|           style={gifvThumbStyle} |         thumbnail = ( | ||||||
|         /> |             <video | ||||||
|       ); |               src={attachment.get('url')} | ||||||
|  |               onClick={this.handleClick} | ||||||
|  |               autoPlay | ||||||
|  |               loop={true} | ||||||
|  |               muted={true} | ||||||
|  |               style={gifvThumbStyle} | ||||||
|  |             /> | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
| @ -192,7 +201,8 @@ const MediaGallery = React.createClass({ | |||||||
|     media: ImmutablePropTypes.list.isRequired, |     media: ImmutablePropTypes.list.isRequired, | ||||||
|     height: React.PropTypes.number.isRequired, |     height: React.PropTypes.number.isRequired, | ||||||
|     onOpenMedia: React.PropTypes.func.isRequired, |     onOpenMedia: React.PropTypes.func.isRequired, | ||||||
|     intl: React.PropTypes.object.isRequired |     intl: React.PropTypes.object.isRequired, | ||||||
|  |     autoPlayGif: React.PropTypes.bool.isRequired | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   mixins: [PureRenderMixin], |   mixins: [PureRenderMixin], | ||||||
| @ -227,7 +237,7 @@ const MediaGallery = React.createClass({ | |||||||
|       ); |       ); | ||||||
|     } else { |     } else { | ||||||
|       const size = media.take(4).size; |       const size = media.take(4).size; | ||||||
|       children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} />); |       children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} autoPlayGif={this.props.autoPlayGif} index={i} size={size} />); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ const Status = React.createClass({ | |||||||
|     onBlock: React.PropTypes.func, |     onBlock: React.PropTypes.func, | ||||||
|     me: React.PropTypes.number, |     me: React.PropTypes.number, | ||||||
|     boostModal: React.PropTypes.bool, |     boostModal: React.PropTypes.bool, | ||||||
|  |     autoPlayGif: React.PropTypes.bool, | ||||||
|     muted: React.PropTypes.bool |     muted: React.PropTypes.bool | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
| @ -79,7 +80,7 @@ const Status = React.createClass({ | |||||||
|       if (status.getIn(['media_attachments', 0, 'type']) === 'video') { |       if (status.getIn(['media_attachments', 0, 'type']) === 'video') { | ||||||
|         media = <VideoPlayer media={status.getIn(['media_attachments', 0])} sensitive={status.get('sensitive')} onOpenVideo={this.props.onOpenVideo} />; |         media = <VideoPlayer media={status.getIn(['media_attachments', 0])} sensitive={status.get('sensitive')} onOpenVideo={this.props.onOpenVideo} />; | ||||||
|       } else { |       } else { | ||||||
|         media = <MediaGallery media={status.get('media_attachments')} sensitive={status.get('sensitive')} height={110} onOpenMedia={this.props.onOpenMedia} />; |         media = <MediaGallery media={status.get('media_attachments')} sensitive={status.get('sensitive')} height={110} onOpenMedia={this.props.onOpenMedia} autoPlayGif={this.props.autoPlayGif} />; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -27,7 +27,8 @@ const makeMapStateToProps = () => { | |||||||
|   const mapStateToProps = (state, props) => ({ |   const mapStateToProps = (state, props) => ({ | ||||||
|     status: getStatus(state, props.id), |     status: getStatus(state, props.id), | ||||||
|     me: state.getIn(['meta', 'me']), |     me: state.getIn(['meta', 'me']), | ||||||
|     boostModal: state.getIn(['meta', 'boost_modal']) |     boostModal: state.getIn(['meta', 'boost_modal']), | ||||||
|  |     autoPlayGif: state.getIn(['meta', 'auto_play_gif']) | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   return mapStateToProps; |   return mapStateToProps; | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ import escapeTextContentForBrowser from 'escape-html'; | |||||||
| import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; | import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; | ||||||
| import IconButton from '../../../components/icon_button'; | import IconButton from '../../../components/icon_button'; | ||||||
| import { Motion, spring } from 'react-motion'; | import { Motion, spring } from 'react-motion'; | ||||||
|  | import { connect } from 'react-redux'; | ||||||
| 
 | 
 | ||||||
| const messages = defineMessages({ | const messages = defineMessages({ | ||||||
|   unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, |   unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, | ||||||
| @ -12,10 +13,19 @@ const messages = defineMessages({ | |||||||
|   requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' } |   requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' } | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | const makeMapStateToProps = () => { | ||||||
|  |   const mapStateToProps = (state, props) => ({ | ||||||
|  |     autoPlayGif: state.getIn(['meta', 'auto_play_gif']) | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   return mapStateToProps; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| const Avatar = React.createClass({ | const Avatar = React.createClass({ | ||||||
| 
 | 
 | ||||||
|   propTypes: { |   propTypes: { | ||||||
|     account: ImmutablePropTypes.map.isRequired |     account: ImmutablePropTypes.map.isRequired, | ||||||
|  |     autoPlayGif: React.PropTypes.bool.isRequired | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   getInitialState () { |   getInitialState () { | ||||||
| @ -37,7 +47,7 @@ const Avatar = React.createClass({ | |||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   render () { |   render () { | ||||||
|     const { account }   = this.props; |     const { account, autoPlayGif }   = this.props; | ||||||
|     const { isHovered } = this.state; |     const { isHovered } = this.state; | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
| @ -53,7 +63,7 @@ const Avatar = React.createClass({ | |||||||
|             onMouseOut={this.handleMouseOut} |             onMouseOut={this.handleMouseOut} | ||||||
|             onFocus={this.handleMouseOver} |             onFocus={this.handleMouseOver} | ||||||
|             onBlur={this.handleMouseOut}> |             onBlur={this.handleMouseOut}> | ||||||
|             <img src={account.get('avatar')} alt={account.get('acct')} style={{ display: 'block', width: '90px', height: '90px' }} /> |             <img src={autoPlayGif || isHovered ? account.get('avatar') : account.get('avatar_static')} alt={account.get('acct')} style={{ display: 'block', width: '90px', height: '90px' }} /> | ||||||
|           </a> |           </a> | ||||||
|         } |         } | ||||||
|       </Motion> |       </Motion> | ||||||
| @ -68,7 +78,8 @@ const Header = React.createClass({ | |||||||
|     account: ImmutablePropTypes.map, |     account: ImmutablePropTypes.map, | ||||||
|     me: React.PropTypes.number.isRequired, |     me: React.PropTypes.number.isRequired, | ||||||
|     onFollow: React.PropTypes.func.isRequired, |     onFollow: React.PropTypes.func.isRequired, | ||||||
|     intl: React.PropTypes.object.isRequired |     intl: React.PropTypes.object.isRequired, | ||||||
|  |     autoPlayGif: React.PropTypes.bool.isRequired | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   mixins: [PureRenderMixin], |   mixins: [PureRenderMixin], | ||||||
| @ -119,7 +130,7 @@ const Header = React.createClass({ | |||||||
|     return ( |     return ( | ||||||
|       <div className='account__header' style={{ backgroundImage: `url(${account.get('header')})` }}> |       <div className='account__header' style={{ backgroundImage: `url(${account.get('header')})` }}> | ||||||
|         <div style={{ padding: '20px 10px' }}> |         <div style={{ padding: '20px 10px' }}> | ||||||
|           <Avatar account={account} /> |           <Avatar account={account} autoPlayGif={this.props.autoPlayGif} /> | ||||||
| 
 | 
 | ||||||
|           <span style={{ display: 'inline-block', fontSize: '20px', lineHeight: '27px', fontWeight: '500' }} className='account__header__display-name' dangerouslySetInnerHTML={displayNameHTML} /> |           <span style={{ display: 'inline-block', fontSize: '20px', lineHeight: '27px', fontWeight: '500' }} className='account__header__display-name' dangerouslySetInnerHTML={displayNameHTML} /> | ||||||
|           <span className='account__header__username' style={{ fontSize: '14px', fontWeight: '400', display: 'block', marginBottom: '10px' }}>@{account.get('acct')} {lockedIcon}</span> |           <span className='account__header__username' style={{ fontSize: '14px', fontWeight: '400', display: 'block', marginBottom: '10px' }}>@{account.get('acct')} {lockedIcon}</span> | ||||||
| @ -134,4 +145,4 @@ const Header = React.createClass({ | |||||||
| 
 | 
 | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| export default injectIntl(Header); | export default connect(makeMapStateToProps)(injectIntl(Header)); | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ const DetailedStatus = React.createClass({ | |||||||
|     status: ImmutablePropTypes.map.isRequired, |     status: ImmutablePropTypes.map.isRequired, | ||||||
|     onOpenMedia: React.PropTypes.func.isRequired, |     onOpenMedia: React.PropTypes.func.isRequired, | ||||||
|     onOpenVideo: React.PropTypes.func.isRequired, |     onOpenVideo: React.PropTypes.func.isRequired, | ||||||
|  |     autoPlayGif: React.PropTypes.bool, | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   mixins: [PureRenderMixin], |   mixins: [PureRenderMixin], | ||||||
| @ -42,7 +43,7 @@ const DetailedStatus = React.createClass({ | |||||||
|       if (status.getIn(['media_attachments', 0, 'type']) === 'video') { |       if (status.getIn(['media_attachments', 0, 'type']) === 'video') { | ||||||
|         media = <VideoPlayer sensitive={status.get('sensitive')} media={status.getIn(['media_attachments', 0])} width={300} height={150} onOpenVideo={this.props.onOpenVideo} autoplay />; |         media = <VideoPlayer sensitive={status.get('sensitive')} media={status.getIn(['media_attachments', 0])} width={300} height={150} onOpenVideo={this.props.onOpenVideo} autoplay />; | ||||||
|       } else { |       } else { | ||||||
|         media = <MediaGallery sensitive={status.get('sensitive')} media={status.get('media_attachments')} height={300} onOpenMedia={this.props.onOpenMedia} />; |         media = <MediaGallery sensitive={status.get('sensitive')} media={status.get('media_attachments')} height={300} onOpenMedia={this.props.onOpenMedia} autoPlayGif={this.props.autoPlayGif} />; | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       media = <CardContainer statusId={status.get('id')} />; |       media = <CardContainer statusId={status.get('id')} />; | ||||||
|  | |||||||
| @ -39,7 +39,8 @@ const makeMapStateToProps = () => { | |||||||
|     ancestorsIds: state.getIn(['timelines', 'ancestors', Number(props.params.statusId)]), |     ancestorsIds: state.getIn(['timelines', 'ancestors', Number(props.params.statusId)]), | ||||||
|     descendantsIds: state.getIn(['timelines', 'descendants', Number(props.params.statusId)]), |     descendantsIds: state.getIn(['timelines', 'descendants', Number(props.params.statusId)]), | ||||||
|     me: state.getIn(['meta', 'me']), |     me: state.getIn(['meta', 'me']), | ||||||
|     boostModal: state.getIn(['meta', 'boost_modal']) |     boostModal: state.getIn(['meta', 'boost_modal']), | ||||||
|  |     autoPlayGif: state.getIn(['meta', 'auto_play_gif']) | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   return mapStateToProps; |   return mapStateToProps; | ||||||
| @ -57,7 +58,8 @@ const Status = React.createClass({ | |||||||
|     ancestorsIds: ImmutablePropTypes.list, |     ancestorsIds: ImmutablePropTypes.list, | ||||||
|     descendantsIds: ImmutablePropTypes.list, |     descendantsIds: ImmutablePropTypes.list, | ||||||
|     me: React.PropTypes.number, |     me: React.PropTypes.number, | ||||||
|     boostModal: React.PropTypes.bool |     boostModal: React.PropTypes.bool, | ||||||
|  |     autoPlayGif: React.PropTypes.bool | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   mixins: [PureRenderMixin], |   mixins: [PureRenderMixin], | ||||||
| @ -126,7 +128,7 @@ const Status = React.createClass({ | |||||||
| 
 | 
 | ||||||
|   render () { |   render () { | ||||||
|     let ancestors, descendants; |     let ancestors, descendants; | ||||||
|     const { status, ancestorsIds, descendantsIds, me } = this.props; |     const { status, ancestorsIds, descendantsIds, me, autoPlayGif } = this.props; | ||||||
| 
 | 
 | ||||||
|     if (status === null) { |     if (status === null) { | ||||||
|       return ( |       return ( | ||||||
| @ -155,7 +157,7 @@ const Status = React.createClass({ | |||||||
|           <div className='scrollable'> |           <div className='scrollable'> | ||||||
|             {ancestors} |             {ancestors} | ||||||
| 
 | 
 | ||||||
|             <DetailedStatus status={status} me={me} onOpenVideo={this.handleOpenVideo} onOpenMedia={this.handleOpenMedia} /> |             <DetailedStatus status={status} autoPlayGif={autoPlayGif} me={me} onOpenVideo={this.handleOpenVideo} onOpenMedia={this.handleOpenMedia} /> | ||||||
|             <ActionBar status={status} me={me} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} onDelete={this.handleDeleteClick} onMention={this.handleMentionClick} onReport={this.handleReport} /> |             <ActionBar status={status} me={me} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} onDelete={this.handleDeleteClick} onMention={this.handleMentionClick} onReport={this.handleReport} /> | ||||||
| 
 | 
 | ||||||
|             {descendants} |             {descendants} | ||||||
|  | |||||||
| @ -24,8 +24,9 @@ class Settings::PreferencesController < ApplicationController | |||||||
| 
 | 
 | ||||||
|     current_user.settings['default_privacy'] = user_params[:setting_default_privacy] |     current_user.settings['default_privacy'] = user_params[:setting_default_privacy] | ||||||
|     current_user.settings['boost_modal'] = user_params[:setting_boost_modal] == '1' |     current_user.settings['boost_modal'] = user_params[:setting_boost_modal] == '1' | ||||||
|  |     current_user.settings['auto_play_gif'] = user_params[:setting_auto_play_gif] == '1' | ||||||
| 
 | 
 | ||||||
|     if current_user.update(user_params.except(:notification_emails, :interactions, :setting_default_privacy, :setting_boost_modal)) |     if current_user.update(user_params.except(:notification_emails, :interactions, :setting_default_privacy, :setting_boost_modal, :setting_auto_play_gif)) | ||||||
|       redirect_to settings_preferences_path, notice: I18n.t('generic.changes_saved_msg') |       redirect_to settings_preferences_path, notice: I18n.t('generic.changes_saved_msg') | ||||||
|     else |     else | ||||||
|       render action: :show |       render action: :show | ||||||
| @ -35,6 +36,6 @@ class Settings::PreferencesController < ApplicationController | |||||||
|   private |   private | ||||||
| 
 | 
 | ||||||
|   def user_params |   def user_params | ||||||
|     params.require(:user).permit(:locale, :setting_default_privacy, :setting_boost_modal, notification_emails: [:follow, :follow_request, :reblog, :favourite, :mention, :digest], interactions: [:must_be_follower, :must_be_following]) |     params.require(:user).permit(:locale, :setting_default_privacy, :setting_boost_modal, :setting_auto_play_gif, notification_emails: [:follow, :follow_request, :reblog, :favourite, :mention, :digest], interactions: [:must_be_follower, :must_be_following]) | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  | |||||||
| @ -30,4 +30,8 @@ class User < ApplicationRecord | |||||||
|   def setting_boost_modal |   def setting_boost_modal | ||||||
|     settings.boost_modal |     settings.boost_modal | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def setting_auto_play_gif | ||||||
|  |     settings.auto_play_gif | ||||||
|  |   end | ||||||
| end | end | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ node(:meta) do | |||||||
|     me: current_account.id, |     me: current_account.id, | ||||||
|     admin: @admin.try(:id), |     admin: @admin.try(:id), | ||||||
|     boost_modal: current_account.user.setting_boost_modal, |     boost_modal: current_account.user.setting_boost_modal, | ||||||
|  |     auto_play_gif: current_account.user.setting_auto_play_gif, | ||||||
|   } |   } | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -25,5 +25,8 @@ | |||||||
|   .fields-group |   .fields-group | ||||||
|     = f.input :setting_boost_modal, as: :boolean, wrapper: :with_label |     = f.input :setting_boost_modal, as: :boolean, wrapper: :with_label | ||||||
| 
 | 
 | ||||||
|  |   .fields-group | ||||||
|  |     = f.input :setting_auto_play_gif, as: :boolean, wrapper: :with_label | ||||||
|  | 
 | ||||||
|   .actions |   .actions | ||||||
|     = f.button :button, t('generic.save_changes'), type: :submit |     = f.button :button, t('generic.save_changes'), type: :submit | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ en: | |||||||
|         note: Bio |         note: Bio | ||||||
|         otp_attempt: Two-factor code |         otp_attempt: Two-factor code | ||||||
|         password: Password |         password: Password | ||||||
|  |         setting_auto_play_gif: Auto-play animated GIFs | ||||||
|         setting_boost_modal: Show confirmation dialog before boosting |         setting_boost_modal: Show confirmation dialog before boosting | ||||||
|         setting_default_privacy: Post privacy |         setting_default_privacy: Post privacy | ||||||
|         severity: Severity |         severity: Severity | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ defaults: &defaults | |||||||
|   open_registrations: true |   open_registrations: true | ||||||
|   closed_registrations_message: '' |   closed_registrations_message: '' | ||||||
|   boost_modal: false |   boost_modal: false | ||||||
|  |   auto_play_gif: true | ||||||
|   notification_emails: |   notification_emails: | ||||||
|     follow: false |     follow: false | ||||||
|     reblog: false |     reblog: false | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user