attachment: ImmutablePropTypes.map.isRequired,
index: 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],
/>
);
} else if (attachment.get('type') === 'gifv') {
- thumbnail = (
- <video
- src={attachment.get('url')}
- onClick={this.handleClick}
- autoPlay={!isIOS()}
- loop={true}
- muted={true}
- style={gifvThumbStyle}
- />
- );
+ if (isIOS() || !this.props.autoPlayGif) {
+ return (
+ <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}>
+ <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>
+ </div>
+ );
+ } else {
+ thumbnail = (
+ <video
+ src={attachment.get('url')}
+ onClick={this.handleClick}
+ autoPlay
+ loop={true}
+ muted={true}
+ style={gifvThumbStyle}
+ />
+ );
+ }
}
return (
media: ImmutablePropTypes.list.isRequired,
height: React.PropTypes.number.isRequired,
onOpenMedia: React.PropTypes.func.isRequired,
- intl: React.PropTypes.object.isRequired
+ intl: React.PropTypes.object.isRequired,
+ autoPlayGif: React.PropTypes.bool.isRequired
},
mixins: [PureRenderMixin],
);
} else {
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 (
onBlock: React.PropTypes.func,
me: React.PropTypes.number,
boostModal: React.PropTypes.bool,
+ autoPlayGif: React.PropTypes.bool,
muted: React.PropTypes.bool
},
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
media = <VideoPlayer media={status.getIn(['media_attachments', 0])} sensitive={status.get('sensitive')} onOpenVideo={this.props.onOpenVideo} />;
} 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} />;
}
}
const mapStateToProps = (state, props) => ({
status: getStatus(state, props.id),
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;
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import IconButton from '../../../components/icon_button';
import { Motion, spring } from 'react-motion';
+import { connect } from 'react-redux';
const messages = defineMessages({
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
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({
propTypes: {
- account: ImmutablePropTypes.map.isRequired
+ account: ImmutablePropTypes.map.isRequired,
+ autoPlayGif: React.PropTypes.bool.isRequired
},
getInitialState () {
},
render () {
- const { account } = this.props;
+ const { account, autoPlayGif } = this.props;
const { isHovered } = this.state;
return (
onMouseOut={this.handleMouseOut}
onFocus={this.handleMouseOver}
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>
}
</Motion>
account: ImmutablePropTypes.map,
me: React.PropTypes.number.isRequired,
onFollow: React.PropTypes.func.isRequired,
- intl: React.PropTypes.object.isRequired
+ intl: React.PropTypes.object.isRequired,
+ autoPlayGif: React.PropTypes.bool.isRequired
},
mixins: [PureRenderMixin],
return (
<div className='account__header' style={{ backgroundImage: `url(${account.get('header')})` }}>
<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 className='account__header__username' style={{ fontSize: '14px', fontWeight: '400', display: 'block', marginBottom: '10px' }}>@{account.get('acct')} {lockedIcon}</span>
});
-export default injectIntl(Header);
+export default connect(makeMapStateToProps)(injectIntl(Header));
status: ImmutablePropTypes.map.isRequired,
onOpenMedia: React.PropTypes.func.isRequired,
onOpenVideo: React.PropTypes.func.isRequired,
+ autoPlayGif: React.PropTypes.bool,
},
mixins: [PureRenderMixin],
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 />;
} 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 {
media = <CardContainer statusId={status.get('id')} />;
ancestorsIds: state.getIn(['timelines', 'ancestors', Number(props.params.statusId)]),
descendantsIds: state.getIn(['timelines', 'descendants', Number(props.params.statusId)]),
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;
ancestorsIds: ImmutablePropTypes.list,
descendantsIds: ImmutablePropTypes.list,
me: React.PropTypes.number,
- boostModal: React.PropTypes.bool
+ boostModal: React.PropTypes.bool,
+ autoPlayGif: React.PropTypes.bool
},
mixins: [PureRenderMixin],
render () {
let ancestors, descendants;
- const { status, ancestorsIds, descendantsIds, me } = this.props;
+ const { status, ancestorsIds, descendantsIds, me, autoPlayGif } = this.props;
if (status === null) {
return (
<div className='scrollable'>
{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} />
{descendants}
current_user.settings['default_privacy'] = user_params[:setting_default_privacy]
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')
else
render action: :show
private
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
def setting_boost_modal
settings.boost_modal
end
+
+ def setting_auto_play_gif
+ settings.auto_play_gif
+ end
end
me: current_account.id,
admin: @admin.try(:id),
boost_modal: current_account.user.setting_boost_modal,
+ auto_play_gif: current_account.user.setting_auto_play_gif,
}
end
.fields-group
= f.input :setting_boost_modal, as: :boolean, wrapper: :with_label
+ .fields-group
+ = f.input :setting_auto_play_gif, as: :boolean, wrapper: :with_label
+
.actions
= f.button :button, t('generic.save_changes'), type: :submit
note: Bio
otp_attempt: Two-factor code
password: Password
+ setting_auto_play_gif: Auto-play animated GIFs
setting_boost_modal: Show confirmation dialog before boosting
setting_default_privacy: Post privacy
severity: Severity
open_registrations: true
closed_registrations_message: ''
boost_modal: false
+ auto_play_gif: true
notification_emails:
follow: false
reblog: false