diff options
Diffstat (limited to 'app/javascript/flavours/glitch/features/public_timeline')
-rw-r--r-- | app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js | 28 | ||||
-rw-r--r-- | app/javascript/flavours/glitch/features/public_timeline/index.js | 133 |
2 files changed, 161 insertions, 0 deletions
diff --git a/app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js new file mode 100644 index 000000000..ec4d74737 --- /dev/null +++ b/app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js @@ -0,0 +1,28 @@ +import { connect } from 'react-redux'; +import ColumnSettings from 'flavours/glitch/features/community_timeline/components/column_settings'; +import { changeSetting } from 'flavours/glitch/actions/settings'; +import { changeColumnParams } from 'flavours/glitch/actions/columns'; + +const mapStateToProps = (state, { columnId }) => { + const uuid = columnId; + const columns = state.getIn(['settings', 'columns']); + const index = columns.findIndex(c => c.get('uuid') === uuid); + + return { + settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'public']), + }; +}; + +const mapDispatchToProps = (dispatch, { columnId }) => { + return { + onChange (key, checked) { + if (columnId) { + dispatch(changeColumnParams(columnId, key, checked)); + } else { + dispatch(changeSetting(['public', ...key], checked)); + } + }, + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings); diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js new file mode 100644 index 000000000..49a5011c0 --- /dev/null +++ b/app/javascript/flavours/glitch/features/public_timeline/index.js @@ -0,0 +1,133 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import PropTypes from 'prop-types'; +import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container'; +import Column from 'flavours/glitch/components/column'; +import ColumnHeader from 'flavours/glitch/components/column_header'; +import { expandPublicTimeline } from 'flavours/glitch/actions/timelines'; +import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; +import ColumnSettingsContainer from './containers/column_settings_container'; +import { connectPublicStream } from 'flavours/glitch/actions/streaming'; + +const messages = defineMessages({ + title: { id: 'column.public', defaultMessage: 'Federated timeline' }, +}); + +const mapStateToProps = (state, { onlyMedia, columnId }) => { + const uuid = columnId; + const columns = state.getIn(['settings', 'columns']); + const index = columns.findIndex(c => c.get('uuid') === uuid); + + return { + hasUnread: state.getIn(['timelines', `public${onlyMedia ? ':media' : ''}`, 'unread']) > 0, + onlyMedia: (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'public', 'other', 'onlyMedia']), + }; +}; + +export default @connect(mapStateToProps) +@injectIntl +class PublicTimeline extends React.PureComponent { + + static defaultProps = { + onlyMedia: false, + }; + + static contextTypes = { + router: PropTypes.object, + }; + + static propTypes = { + dispatch: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, + columnId: PropTypes.string, + multiColumn: PropTypes.bool, + hasUnread: PropTypes.bool, + onlyMedia: PropTypes.bool, + }; + + handlePin = () => { + const { columnId, dispatch, onlyMedia } = this.props; + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('PUBLIC', { other: { onlyMedia } })); + } + } + + handleMove = (dir) => { + const { columnId, dispatch } = this.props; + dispatch(moveColumn(columnId, dir)); + } + + handleHeaderClick = () => { + this.column.scrollTop(); + } + + componentDidMount () { + const { dispatch, onlyMedia } = this.props; + + dispatch(expandPublicTimeline({ onlyMedia })); + this.disconnect = dispatch(connectPublicStream({ onlyMedia })); + } + + componentDidUpdate (prevProps) { + if (prevProps.onlyMedia !== this.props.onlyMedia) { + const { dispatch, onlyMedia } = this.props; + + this.disconnect(); + dispatch(expandPublicTimeline({ onlyMedia })); + this.disconnect = dispatch(connectPublicStream({ onlyMedia })); + } + } + + componentWillUnmount () { + if (this.disconnect) { + this.disconnect(); + this.disconnect = null; + } + } + + setRef = c => { + this.column = c; + } + + handleLoadMore = maxId => { + const { dispatch, onlyMedia } = this.props; + + dispatch(expandPublicTimeline({ maxId, onlyMedia })); + } + + render () { + const { intl, columnId, hasUnread, multiColumn, onlyMedia } = this.props; + const pinned = !!columnId; + + return ( + <Column bindToDocument={!multiColumn} ref={this.setRef} name='federated' label={intl.formatMessage(messages.title)}> + <ColumnHeader + icon='globe' + active={hasUnread} + title={intl.formatMessage(messages.title)} + onPin={this.handlePin} + onMove={this.handleMove} + onClick={this.handleHeaderClick} + pinned={pinned} + multiColumn={multiColumn} + > + <ColumnSettingsContainer columnId={columnId} /> + </ColumnHeader> + + <StatusListContainer + timelineId={`public${onlyMedia ? ':media' : ''}`} + onLoadMore={this.handleLoadMore} + trackScroll={!pinned} + scrollKey={`public_timeline-${columnId}`} + emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up' />} + bindToDocument={!multiColumn} + /> + </Column> + ); + } + +} |