From 5770d461b21cf5b6a8adcaa44d19832e11289960 Mon Sep 17 00:00:00 2001 From: kibigo! Date: Thu, 13 Jul 2017 02:40:16 -0700 Subject: Moved glitch containers and commented unused files --- .../glitch/components/compose/advanced_options.js | 137 ----------- .../compose/advanced_options/container.js | 22 ++ .../components/compose/advanced_options/index.js | 137 +++++++++++ .../glitch/components/notification/container.js | 21 ++ .../glitch/components/notification/index.js | 2 +- .../glitch/components/settings/container.js | 27 +++ .../glitch/components/status/container.js | 252 +++++++++++++++++++++ app/javascript/glitch/components/status/index.js | 4 +- app/javascript/glitch/components/status/player.js | 199 ++++++++++++++++ .../glitch/components/status/video_player.js | 199 ---------------- 10 files changed, 661 insertions(+), 339 deletions(-) delete mode 100644 app/javascript/glitch/components/compose/advanced_options.js create mode 100644 app/javascript/glitch/components/compose/advanced_options/container.js create mode 100644 app/javascript/glitch/components/compose/advanced_options/index.js create mode 100644 app/javascript/glitch/components/notification/container.js create mode 100644 app/javascript/glitch/components/settings/container.js create mode 100644 app/javascript/glitch/components/status/container.js create mode 100644 app/javascript/glitch/components/status/player.js delete mode 100644 app/javascript/glitch/components/status/video_player.js (limited to 'app/javascript/glitch/components') diff --git a/app/javascript/glitch/components/compose/advanced_options.js b/app/javascript/glitch/components/compose/advanced_options.js deleted file mode 100644 index 17fc1d801..000000000 --- a/app/javascript/glitch/components/compose/advanced_options.js +++ /dev/null @@ -1,137 +0,0 @@ -// Package imports // -import React from 'react'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import Toggle from 'react-toggle'; -import { injectIntl, defineMessages } from 'react-intl'; - -// Mastodon imports // -import IconButton from '../../../mastodon/components/icon_button'; - -const messages = defineMessages({ - local_only_short: { id: 'advanced-options.local-only.short', defaultMessage: 'Local-only' }, - local_only_long: { id: 'advanced-options.local-only.long', defaultMessage: 'Do not post to other instances' }, - advanced_options_icon_title: { id: 'advanced_options.icon_title', defaultMessage: 'Advanced options' }, -}); - -const iconStyle = { - height: null, - lineHeight: '27px', -}; - -class AdvancedOptionToggle extends React.PureComponent { - - static propTypes = { - onChange: PropTypes.func.isRequired, - active: PropTypes.bool.isRequired, - name: PropTypes.string.isRequired, - shortText: PropTypes.string.isRequired, - longText: PropTypes.string.isRequired, - } - - onToggle = () => { - this.props.onChange(this.props.name); - } - - render() { - const { active, shortText, longText } = this.props; - return ( -
-
- -
-
- {shortText} - {longText} -
-
- ); - } - -} - -@injectIntl -export default class ComposeAdvancedOptions extends React.PureComponent { - - static propTypes = { - values: ImmutablePropTypes.contains({ - do_not_federate: PropTypes.bool.isRequired, - }).isRequired, - onChange: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - }; - - onToggleDropdown = () => { - this.setState({ open: !this.state.open }); - }; - - onGlobalClick = (e) => { - if (e.target !== this.node && !this.node.contains(e.target) && this.state.open) { - this.setState({ open: false }); - } - } - - componentDidMount () { - window.addEventListener('click', this.onGlobalClick); - window.addEventListener('touchstart', this.onGlobalClick); - } - - componentWillUnmount () { - window.removeEventListener('click', this.onGlobalClick); - window.removeEventListener('touchstart', this.onGlobalClick); - } - - state = { - open: false, - }; - - handleClick = (e) => { - const option = e.currentTarget.getAttribute('data-index'); - e.preventDefault(); - this.props.onChange(option); - } - - setRef = (c) => { - this.node = c; - } - - render () { - const { open } = this.state; - const { intl, values } = this.props; - - const options = [ - { icon: 'wifi', shortText: messages.local_only_short, longText: messages.local_only_long, key: 'do_not_federate' }, - ]; - - const anyEnabled = values.some((enabled) => enabled); - const optionElems = options.map((option) => { - return ( - - ); - }); - - return (
-
- -
-
- {optionElems} -
-
); - } - -} diff --git a/app/javascript/glitch/components/compose/advanced_options/container.js b/app/javascript/glitch/components/compose/advanced_options/container.js new file mode 100644 index 000000000..10804454a --- /dev/null +++ b/app/javascript/glitch/components/compose/advanced_options/container.js @@ -0,0 +1,22 @@ +// Package imports // +import { connect } from 'react-redux'; + +// Mastodon imports // +import { toggleComposeAdvancedOption } from '../../../../mastodon/actions/compose'; + +// Our imports // +import ComposeAdvancedOptions from '.'; + +const mapStateToProps = state => ({ + values: state.getIn(['compose', 'advanced_options']), +}); + +const mapDispatchToProps = dispatch => ({ + + onChange (option) { + dispatch(toggleComposeAdvancedOption(option)); + }, + +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ComposeAdvancedOptions); diff --git a/app/javascript/glitch/components/compose/advanced_options/index.js b/app/javascript/glitch/components/compose/advanced_options/index.js new file mode 100644 index 000000000..dabf66095 --- /dev/null +++ b/app/javascript/glitch/components/compose/advanced_options/index.js @@ -0,0 +1,137 @@ +// Package imports // +import React from 'react'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import Toggle from 'react-toggle'; +import { injectIntl, defineMessages } from 'react-intl'; + +// Mastodon imports // +import IconButton from '../../../../mastodon/components/icon_button'; + +const messages = defineMessages({ + local_only_short: { id: 'advanced-options.local-only.short', defaultMessage: 'Local-only' }, + local_only_long: { id: 'advanced-options.local-only.long', defaultMessage: 'Do not post to other instances' }, + advanced_options_icon_title: { id: 'advanced_options.icon_title', defaultMessage: 'Advanced options' }, +}); + +const iconStyle = { + height: null, + lineHeight: '27px', +}; + +class AdvancedOptionToggle extends React.PureComponent { + + static propTypes = { + onChange: PropTypes.func.isRequired, + active: PropTypes.bool.isRequired, + name: PropTypes.string.isRequired, + shortText: PropTypes.string.isRequired, + longText: PropTypes.string.isRequired, + } + + onToggle = () => { + this.props.onChange(this.props.name); + } + + render() { + const { active, shortText, longText } = this.props; + return ( +
+
+ +
+
+ {shortText} + {longText} +
+
+ ); + } + +} + +@injectIntl +export default class ComposeAdvancedOptions extends React.PureComponent { + + static propTypes = { + values: ImmutablePropTypes.contains({ + do_not_federate: PropTypes.bool.isRequired, + }).isRequired, + onChange: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, + }; + + onToggleDropdown = () => { + this.setState({ open: !this.state.open }); + }; + + onGlobalClick = (e) => { + if (e.target !== this.node && !this.node.contains(e.target) && this.state.open) { + this.setState({ open: false }); + } + } + + componentDidMount () { + window.addEventListener('click', this.onGlobalClick); + window.addEventListener('touchstart', this.onGlobalClick); + } + + componentWillUnmount () { + window.removeEventListener('click', this.onGlobalClick); + window.removeEventListener('touchstart', this.onGlobalClick); + } + + state = { + open: false, + }; + + handleClick = (e) => { + const option = e.currentTarget.getAttribute('data-index'); + e.preventDefault(); + this.props.onChange(option); + } + + setRef = (c) => { + this.node = c; + } + + render () { + const { open } = this.state; + const { intl, values } = this.props; + + const options = [ + { icon: 'wifi', shortText: messages.local_only_short, longText: messages.local_only_long, key: 'do_not_federate' }, + ]; + + const anyEnabled = values.some((enabled) => enabled); + const optionElems = options.map((option) => { + return ( + + ); + }); + + return (
+
+ +
+
+ {optionElems} +
+
); + } + +} diff --git a/app/javascript/glitch/components/notification/container.js b/app/javascript/glitch/components/notification/container.js new file mode 100644 index 000000000..c58ef4bd2 --- /dev/null +++ b/app/javascript/glitch/components/notification/container.js @@ -0,0 +1,21 @@ +// Package imports // +import { connect } from 'react-redux'; + +// Mastodon imports // +import { makeGetNotification } from '../../../mastodon/selectors'; + +// Our imports // +import Notification from '.'; + +const makeMapStateToProps = () => { + const getNotification = makeGetNotification(); + + const mapStateToProps = (state, props) => ({ + notification: getNotification(state, props.notification, props.accountId), + settings: state.get('local_settings'), + }); + + return mapStateToProps; +}; + +export default connect(makeMapStateToProps)(Notification); diff --git a/app/javascript/glitch/components/notification/index.js b/app/javascript/glitch/components/notification/index.js index 3f424d85d..34e03cdca 100644 --- a/app/javascript/glitch/components/notification/index.js +++ b/app/javascript/glitch/components/notification/index.js @@ -11,7 +11,7 @@ import Permalink from '../../../mastodon/components/permalink'; import emojify from '../../../mastodon/emoji'; // Our imports // -import StatusContainer from '../../containers/status'; +import StatusContainer from '../status'; export default class Notification extends ImmutablePureComponent { diff --git a/app/javascript/glitch/components/settings/container.js b/app/javascript/glitch/components/settings/container.js new file mode 100644 index 000000000..6034935eb --- /dev/null +++ b/app/javascript/glitch/components/settings/container.js @@ -0,0 +1,27 @@ +// Package imports // +import { connect } from 'react-redux'; + +// Mastodon imports // +import { closeModal } from '../../../mastodon/actions/modal'; + +// Our imports // +import { changeLocalSetting } from '../../actions/local_settings'; +import Settings from '../../components/settings'; + +const mapStateToProps = state => ({ + settings: state.get('local_settings'), +}); + +const mapDispatchToProps = dispatch => ({ + toggleSetting (setting, e) { + dispatch(changeLocalSetting(setting, e.target.checked)); + }, + changeSetting (setting, e) { + dispatch(changeLocalSetting(setting, e.target.value)); + }, + onClose () { + dispatch(closeModal()); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Settings); diff --git a/app/javascript/glitch/components/status/container.js b/app/javascript/glitch/components/status/container.js new file mode 100644 index 000000000..a8aa6efe9 --- /dev/null +++ b/app/javascript/glitch/components/status/container.js @@ -0,0 +1,252 @@ +/* + +`` +=================== + +Original file by @gargron@mastodon.social et al as part of +tootsuite/mastodon. Documentation by @kibi@glitch.social. The code +detecting reblogs has been moved here from . + +*/ + + /* * * * */ + +/* + +Imports: +-------- + +*/ + +// Package imports // +import React from 'react'; +import { connect } from 'react-redux'; +import { + defineMessages, + injectIntl, + FormattedMessage, +} from 'react-intl'; + +// Mastodon imports // +import { makeGetStatus } from '../../../mastodon/selectors'; +import { + replyCompose, + mentionCompose, +} from '../../../mastodon/actions/compose'; +import { + reblog, + favourite, + unreblog, + unfavourite, +} from '../../../mastodon/actions/interactions'; +import { + blockAccount, + muteAccount, +} from '../../../mastodon/actions/accounts'; +import { + muteStatus, + unmuteStatus, + deleteStatus, +} from '../../../mastodon/actions/statuses'; +import { initReport } from '../../../mastodon/actions/reports'; +import { openModal } from '../../../mastodon/actions/modal'; + +// Our imports // +import Status from '.'; + + /* * * * */ + +/* + +Inital setup: +------------- + +The `messages` constant is used to define any messages that we will +need in our component. In our case, these are the various confirmation +messages used with statuses. + +*/ + +const messages = defineMessages({ + deleteConfirm : { + id : 'confirmations.delete.confirm', + defaultMessage : 'Delete', + }, + deleteMessage : { + id : 'confirmations.delete.message', + defaultMessage : 'Are you sure you want to delete this status?', + }, + blockConfirm : { + id : 'confirmations.block.confirm', + defaultMessage : 'Block', + }, + muteConfirm : { + id : 'confirmations.mute.confirm', + defaultMessage : 'Mute', + }, +}); + + /* * * * */ + +/* + +State mapping: +-------------- + +The `mapStateToProps()` function maps various state properties to the +props of our component. We wrap this in a `makeMapStateToProps()` +function to give us closure and preserve `getStatus()` across function +calls. + +*/ + +const makeMapStateToProps = () => { + const getStatus = makeGetStatus(); + + const mapStateToProps = (state, ownProps) => { + + let status = getStatus(state, ownProps.id); + let reblogStatus = status.get('reblog', null); + let account = undefined; + let prepend = undefined; + +/* + +Here we process reblogs. If our status is a reblog, then we create a +`prependMessage` to pass along to our `` along with the +reblogger's `account`, and set `coreStatus` (the one we will actually +render) to the status which has been reblogged. + +*/ + + if (reblogStatus !== null && typeof reblogStatus === 'object') { + account = status.get('account'); + status = reblogStatus; + prepend = 'reblogged_by'; + } + +/* + +Here are the props we pass to ``. + +*/ + + return { + status : status, + account : account || ownProps.account, + me : state.getIn(['meta', 'me']), + settings : state.get('local_settings'), + prepend : prepend || ownProps.prepend, + reblogModal : state.getIn(['meta', 'boost_modal']), + deleteModal : state.getIn(['meta', 'delete_modal']), + autoPlayGif : state.getIn(['meta', 'auto_play_gif']), + }; + }; + + return mapStateToProps; +}; + + /* * * * */ + +/* + +Dispatch mapping: +----------------- + +The `mapDispatchToProps()` function maps dispatches to our store to the +various props of our component. We need to provide dispatches for all +of the things you can do with a status: reply, reblog, favourite, et +cetera. + +For a few of these dispatches, we open up confirmation modals; the rest +just immediately execute their corresponding actions. + +*/ + +const mapDispatchToProps = (dispatch, { intl }) => ({ + + onReply (status, router) { + dispatch(replyCompose(status, router)); + }, + + onModalReblog (status) { + dispatch(reblog(status)); + }, + + onReblog (status, e) { + if (status.get('reblogged')) { + dispatch(unreblog(status)); + } else { + if (e.shiftKey || !this.reblogModal) { + this.onModalReblog(status); + } else { + dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog })); + } + } + }, + + onFavourite (status) { + if (status.get('favourited')) { + dispatch(unfavourite(status)); + } else { + dispatch(favourite(status)); + } + }, + + onDelete (status) { + if (!this.deleteModal) { + dispatch(deleteStatus(status.get('id'))); + } else { + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.deleteMessage), + confirm: intl.formatMessage(messages.deleteConfirm), + onConfirm: () => dispatch(deleteStatus(status.get('id'))), + })); + } + }, + + onMention (account, router) { + dispatch(mentionCompose(account, router)); + }, + + onOpenMedia (media, index) { + dispatch(openModal('MEDIA', { media, index })); + }, + + onOpenVideo (media, time) { + dispatch(openModal('VIDEO', { media, time })); + }, + + onBlock (account) { + dispatch(openModal('CONFIRM', { + message: @{account.get('acct')} }} />, + confirm: intl.formatMessage(messages.blockConfirm), + onConfirm: () => dispatch(blockAccount(account.get('id'))), + })); + }, + + onReport (status) { + dispatch(initReport(status.get('account'), status)); + }, + + onMute (account) { + dispatch(openModal('CONFIRM', { + message: @{account.get('acct')} }} />, + confirm: intl.formatMessage(messages.muteConfirm), + onConfirm: () => dispatch(muteAccount(account.get('id'))), + })); + }, + + onMuteConversation (status) { + if (status.get('muted')) { + dispatch(unmuteStatus(status.get('id'))); + } else { + dispatch(muteStatus(status.get('id'))); + } + }, + +}); + +export default injectIntl( + connect(makeMapStateToProps, mapDispatchToProps)(Status) +); diff --git a/app/javascript/glitch/components/status/index.js b/app/javascript/glitch/components/status/index.js index 12ea0e9aa..1d135754a 100644 --- a/app/javascript/glitch/components/status/index.js +++ b/app/javascript/glitch/components/status/index.js @@ -46,7 +46,7 @@ import StatusHeader from './header'; import StatusContent from './content'; import StatusActionBar from './action_bar'; import StatusGallery from './gallery'; -import StatusVideoPlayer from './video_player'; +import StatusPlayer from './player'; /* * * * */ @@ -619,7 +619,7 @@ backgrounds for collapsed statuses are enabled. attachments.getIn([0, 'type']) === 'video' ) { media = ( // Media type is 'video' - { + this.setState({ muted: !this.state.muted }); + } + + handleVideoClick = (e) => { + e.stopPropagation(); + + const node = this.video; + + if (node.paused) { + node.play(); + } else { + node.pause(); + } + } + + handleOpen = () => { + this.setState({ preview: !this.state.preview }); + } + + handleVisibility = () => { + this.setState({ + visible: !this.state.visible, + preview: true, + }); + } + + handleExpand = () => { + this.video.pause(); + this.props.onOpenVideo(this.props.media, this.video.currentTime); + } + + setRef = (c) => { + this.video = c; + } + + handleLoadedData = () => { + if (('WebkitAppearance' in document.documentElement.style && this.video.audioTracks.length === 0) || this.video.mozHasAudio === false) { + this.setState({ hasAudio: false }); + } + } + + handleVideoError = () => { + this.setState({ videoError: true }); + } + + componentDidMount () { + if (!this.video) { + return; + } + + this.video.addEventListener('loadeddata', this.handleLoadedData); + this.video.addEventListener('error', this.handleVideoError); + } + + componentDidUpdate () { + if (!this.video) { + return; + } + + this.video.addEventListener('loadeddata', this.handleLoadedData); + this.video.addEventListener('error', this.handleVideoError); + } + + componentWillUnmount () { + if (!this.video) { + return; + } + + this.video.removeEventListener('loadeddata', this.handleLoadedData); + this.video.removeEventListener('error', this.handleVideoError); + } + + render () { + const { media, intl, letterbox, fullwidth, height, sensitive, autoplay } = this.props; + + let spoilerButton = ( +
+ +
+ ); + + let expandButton = ( +
+ +
+ ); + + let muteButton = ''; + + if (this.state.hasAudio) { + muteButton = ( +
+ +
+ ); + } + + if (!this.state.visible) { + if (sensitive) { + return ( +
+ {spoilerButton} + + +
+ ); + } else { + return ( +
+ {spoilerButton} + + +
+ ); + } + } + + if (this.state.preview && !autoplay) { + return ( +
+ {spoilerButton} +
+
+ ); + } + + if (this.state.videoError) { + return ( +
+ +
+ ); + } + + return ( +
+ {spoilerButton} + {muteButton} + {expandButton} + +
+ ); + } + +} diff --git a/app/javascript/glitch/components/status/video_player.js b/app/javascript/glitch/components/status/video_player.js deleted file mode 100644 index 6583107c8..000000000 --- a/app/javascript/glitch/components/status/video_player.js +++ /dev/null @@ -1,199 +0,0 @@ -// Package imports // -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; - -// Mastodon imports // -import IconButton from '../../../mastodon/components/icon_button'; -import { isIOS } from '../../../mastodon/is_mobile'; - -const messages = defineMessages({ - toggle_sound: { id: 'video_player.toggle_sound', defaultMessage: 'Toggle sound' }, - toggle_visible: { id: 'video_player.toggle_visible', defaultMessage: 'Toggle visibility' }, - expand_video: { id: 'video_player.expand', defaultMessage: 'Expand video' }, -}); - -@injectIntl -export default class StatusVideoPlayer extends React.PureComponent { - - static propTypes = { - media: ImmutablePropTypes.map.isRequired, - letterbox: PropTypes.bool, - fullwidth: PropTypes.bool, - height: PropTypes.number, - sensitive: PropTypes.bool, - intl: PropTypes.object.isRequired, - autoplay: PropTypes.bool, - onOpenVideo: PropTypes.func.isRequired, - }; - - static defaultProps = { - height: 110, - }; - - state = { - visible: !this.props.sensitive, - preview: true, - muted: true, - hasAudio: true, - videoError: false, - }; - - handleClick = () => { - this.setState({ muted: !this.state.muted }); - } - - handleVideoClick = (e) => { - e.stopPropagation(); - - const node = this.video; - - if (node.paused) { - node.play(); - } else { - node.pause(); - } - } - - handleOpen = () => { - this.setState({ preview: !this.state.preview }); - } - - handleVisibility = () => { - this.setState({ - visible: !this.state.visible, - preview: true, - }); - } - - handleExpand = () => { - this.video.pause(); - this.props.onOpenVideo(this.props.media, this.video.currentTime); - } - - setRef = (c) => { - this.video = c; - } - - handleLoadedData = () => { - if (('WebkitAppearance' in document.documentElement.style && this.video.audioTracks.length === 0) || this.video.mozHasAudio === false) { - this.setState({ hasAudio: false }); - } - } - - handleVideoError = () => { - this.setState({ videoError: true }); - } - - componentDidMount () { - if (!this.video) { - return; - } - - this.video.addEventListener('loadeddata', this.handleLoadedData); - this.video.addEventListener('error', this.handleVideoError); - } - - componentDidUpdate () { - if (!this.video) { - return; - } - - this.video.addEventListener('loadeddata', this.handleLoadedData); - this.video.addEventListener('error', this.handleVideoError); - } - - componentWillUnmount () { - if (!this.video) { - return; - } - - this.video.removeEventListener('loadeddata', this.handleLoadedData); - this.video.removeEventListener('error', this.handleVideoError); - } - - render () { - const { media, intl, letterbox, fullwidth, height, sensitive, autoplay } = this.props; - - let spoilerButton = ( -
- -
- ); - - let expandButton = ( -
- -
- ); - - let muteButton = ''; - - if (this.state.hasAudio) { - muteButton = ( -
- -
- ); - } - - if (!this.state.visible) { - if (sensitive) { - return ( -
- {spoilerButton} - - -
- ); - } else { - return ( -
- {spoilerButton} - - -
- ); - } - } - - if (this.state.preview && !autoplay) { - return ( -
- {spoilerButton} -
-
- ); - } - - if (this.state.videoError) { - return ( -
- -
- ); - } - - return ( -
- {spoilerButton} - {muteButton} - {expandButton} - -
- ); - } - -} -- cgit