Compare commits
4 Commits
main
...
unify-time
Author | SHA1 | Date |
---|---|---|
kibigo! | 4d0fde3d93 | |
kibigo! | ff0ecca84c | |
kibigo! | cdd7f792cb | |
kibigo! | 77908849bb |
|
@ -1,144 +1,44 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import StatusListContainer from '../ui/containers/status_list_container';
|
|
||||||
import Column from '../../components/column';
|
|
||||||
import ColumnHeader from '../../components/column_header';
|
|
||||||
import {
|
import {
|
||||||
refreshCommunityTimeline,
|
refreshCommunityTimeline,
|
||||||
expandCommunityTimeline,
|
expandCommunityTimeline,
|
||||||
updateTimeline,
|
|
||||||
deleteFromTimelines,
|
|
||||||
connectTimeline,
|
|
||||||
disconnectTimeline,
|
|
||||||
} from '../../actions/timelines';
|
} from '../../actions/timelines';
|
||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||||
import createStream from '../../stream';
|
import Timeline from '../timeline';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'column.community', defaultMessage: 'Local timeline' },
|
title: { id: 'column.community', defaultMessage: 'Local timeline' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
hasUnread: state.getIn(['timelines', 'community', 'unread']) > 0,
|
|
||||||
streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']),
|
|
||||||
accessToken: state.getIn(['meta', 'access_token']),
|
|
||||||
});
|
|
||||||
|
|
||||||
@connect(mapStateToProps)
|
|
||||||
@injectIntl
|
@injectIntl
|
||||||
export default class CommunityTimeline extends React.PureComponent {
|
export default class CommunityTimeline extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
streamingAPIBaseURL: PropTypes.string.isRequired,
|
|
||||||
accessToken: PropTypes.string.isRequired,
|
|
||||||
hasUnread: PropTypes.bool,
|
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePin = () => {
|
|
||||||
const { columnId, dispatch } = this.props;
|
|
||||||
|
|
||||||
if (columnId) {
|
|
||||||
dispatch(removeColumn(columnId));
|
|
||||||
} else {
|
|
||||||
dispatch(addColumn('COMMUNITY', {}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMove = (dir) => {
|
|
||||||
const { columnId, dispatch } = this.props;
|
|
||||||
dispatch(moveColumn(columnId, dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
handleHeaderClick = () => {
|
|
||||||
this.column.scrollTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
const { dispatch, streamingAPIBaseURL, accessToken } = this.props;
|
|
||||||
|
|
||||||
dispatch(refreshCommunityTimeline());
|
|
||||||
|
|
||||||
if (typeof this._subscription !== 'undefined') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._subscription = createStream(streamingAPIBaseURL, accessToken, 'public:local', {
|
|
||||||
|
|
||||||
connected () {
|
|
||||||
dispatch(connectTimeline('community'));
|
|
||||||
},
|
|
||||||
|
|
||||||
reconnected () {
|
|
||||||
dispatch(connectTimeline('community'));
|
|
||||||
},
|
|
||||||
|
|
||||||
disconnected () {
|
|
||||||
dispatch(disconnectTimeline('community'));
|
|
||||||
},
|
|
||||||
|
|
||||||
received (data) {
|
|
||||||
switch(data.event) {
|
|
||||||
case 'update':
|
|
||||||
dispatch(updateTimeline('community', JSON.parse(data.payload)));
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
dispatch(deleteFromTimelines(data.payload));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount () {
|
|
||||||
if (typeof this._subscription !== 'undefined') {
|
|
||||||
this._subscription.close();
|
|
||||||
this._subscription = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setRef = c => {
|
|
||||||
this.column = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = () => {
|
|
||||||
this.props.dispatch(expandCommunityTimeline());
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, hasUnread, columnId, multiColumn } = this.props;
|
const { intl, columnId, multiColumn } = this.props;
|
||||||
const pinned = !!columnId;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column ref={this.setRef}>
|
<Timeline
|
||||||
<ColumnHeader
|
expand={expandCommunityTimeline}
|
||||||
icon='users'
|
refresh={refreshCommunityTimeline}
|
||||||
active={hasUnread}
|
streamId='public:local'
|
||||||
title={intl.formatMessage(messages.title)}
|
columnName='COMMUNITY'
|
||||||
onPin={this.handlePin}
|
columnId={columnId}
|
||||||
onMove={this.handleMove}
|
mulitColumn={multiColumn}
|
||||||
onClick={this.handleHeaderClick}
|
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
||||||
pinned={pinned}
|
icon='users'
|
||||||
multiColumn={multiColumn}
|
title={intl.formatMessage(messages.title)}
|
||||||
>
|
settings={<ColumnSettingsContainer />}
|
||||||
<ColumnSettingsContainer />
|
scrollName='community_timeline'
|
||||||
</ColumnHeader>
|
timelineId='community'
|
||||||
|
/>
|
||||||
<StatusListContainer
|
|
||||||
trackScroll={!pinned}
|
|
||||||
scrollKey={`community_timeline-${columnId}`}
|
|
||||||
timelineId='community'
|
|
||||||
loadMore={this.handleLoadMore}
|
|
||||||
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,138 +1,53 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import StatusListContainer from '../ui/containers/status_list_container';
|
|
||||||
import Column from '../../components/column';
|
|
||||||
import ColumnHeader from '../../components/column_header';
|
|
||||||
import {
|
import {
|
||||||
refreshHashtagTimeline,
|
refreshHashtagTimeline,
|
||||||
expandHashtagTimeline,
|
expandHashtagTimeline,
|
||||||
updateTimeline,
|
|
||||||
deleteFromTimelines,
|
|
||||||
} from '../../actions/timelines';
|
} from '../../actions/timelines';
|
||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import createStream from '../../stream';
|
import Timeline from '../timeline';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
hasUnread: state.getIn(['timelines', 'tag', 'unread']) > 0,
|
|
||||||
streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']),
|
|
||||||
accessToken: state.getIn(['meta', 'access_token']),
|
|
||||||
});
|
|
||||||
|
|
||||||
@connect(mapStateToProps)
|
|
||||||
export default class HashtagTimeline extends React.PureComponent {
|
export default class HashtagTimeline extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
params: PropTypes.object.isRequired,
|
params: PropTypes.object.isRequired,
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
streamingAPIBaseURL: PropTypes.string.isRequired,
|
|
||||||
accessToken: PropTypes.string.isRequired,
|
|
||||||
hasUnread: PropTypes.bool,
|
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePin = () => {
|
componentWillMount () {
|
||||||
const { columnId, dispatch } = this.props;
|
const id = this.props.params.id;
|
||||||
|
this.expand = () => expandHashtagTimeline(id);
|
||||||
if (columnId) {
|
this.refresh = () => refreshHashtagTimeline(id);
|
||||||
dispatch(removeColumn(columnId));
|
|
||||||
} else {
|
|
||||||
dispatch(addColumn('HASHTAG', { id: this.props.params.id }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMove = (dir) => {
|
|
||||||
const { columnId, dispatch } = this.props;
|
|
||||||
dispatch(moveColumn(columnId, dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
handleHeaderClick = () => {
|
|
||||||
this.column.scrollTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribe (dispatch, id) {
|
|
||||||
const { streamingAPIBaseURL, accessToken } = this.props;
|
|
||||||
|
|
||||||
this.subscription = createStream(streamingAPIBaseURL, accessToken, `hashtag&tag=${id}`, {
|
|
||||||
|
|
||||||
received (data) {
|
|
||||||
switch(data.event) {
|
|
||||||
case 'update':
|
|
||||||
dispatch(updateTimeline(`hashtag:${id}`, JSON.parse(data.payload)));
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
dispatch(deleteFromTimelines(data.payload));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_unsubscribe () {
|
|
||||||
if (typeof this.subscription !== 'undefined') {
|
|
||||||
this.subscription.close();
|
|
||||||
this.subscription = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
const { dispatch } = this.props;
|
|
||||||
const { id } = this.props.params;
|
|
||||||
|
|
||||||
dispatch(refreshHashtagTimeline(id));
|
|
||||||
this._subscribe(dispatch, id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps (nextProps) {
|
||||||
if (nextProps.params.id !== this.props.params.id) {
|
if (nextProps.params.id !== this.props.params.id) {
|
||||||
this.props.dispatch(refreshHashtagTimeline(nextProps.params.id));
|
const id = nextProps.params.id;
|
||||||
this._unsubscribe();
|
this.expand = () => expandHashtagTimeline(id);
|
||||||
this._subscribe(this.props.dispatch, nextProps.params.id);
|
this.refresh = () => refreshHashtagTimeline(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
|
||||||
this._unsubscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
setRef = c => {
|
|
||||||
this.column = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = () => {
|
|
||||||
this.props.dispatch(expandHashtagTimeline(this.props.params.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { hasUnread, columnId, multiColumn } = this.props;
|
const { columnId, multiColumn } = this.props;
|
||||||
const { id } = this.props.params;
|
const { id } = this.props.params;
|
||||||
const pinned = !!columnId;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column ref={this.setRef}>
|
<Timeline
|
||||||
<ColumnHeader
|
expand={this.expand}
|
||||||
icon='hashtag'
|
refresh={this.refresh}
|
||||||
active={hasUnread}
|
streamId={`hashtag&tag=${id}`}
|
||||||
title={id}
|
columnName='HASHTAG'
|
||||||
onPin={this.handlePin}
|
columnProps={{ id }}
|
||||||
onMove={this.handleMove}
|
columnId={columnId}
|
||||||
onClick={this.handleHeaderClick}
|
mulitColumn={multiColumn}
|
||||||
pinned={pinned}
|
emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
|
||||||
multiColumn={multiColumn}
|
icon='hashtag'
|
||||||
showBackButton
|
title={id}
|
||||||
/>
|
scrollName='hashtag_timeline'
|
||||||
|
timelineId={`hashtag:${id}`}
|
||||||
<StatusListContainer
|
/>
|
||||||
trackScroll={!pinned}
|
|
||||||
scrollKey={`hashtag_timeline-${columnId}`}
|
|
||||||
timelineId={`hashtag:${id}`}
|
|
||||||
loadMore={this.handleLoadMore}
|
|
||||||
emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,9 @@ import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { expandHomeTimeline } from '../../actions/timelines';
|
import { expandHomeTimeline } from '../../actions/timelines';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import StatusListContainer from '../ui/containers/status_list_container';
|
|
||||||
import Column from '../../components/column';
|
|
||||||
import ColumnHeader from '../../components/column_header';
|
|
||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||||
|
import Timeline from '../timeline';
|
||||||
import Link from 'react-router-dom/Link';
|
import Link from 'react-router-dom/Link';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -15,7 +12,6 @@ const messages = defineMessages({
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0,
|
|
||||||
hasFollows: state.getIn(['accounts_counters', state.getIn(['meta', 'me']), 'following_count']) > 0,
|
hasFollows: state.getIn(['accounts_counters', state.getIn(['meta', 'me']), 'following_count']) > 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -24,44 +20,14 @@ const mapStateToProps = state => ({
|
||||||
export default class HomeTimeline extends React.PureComponent {
|
export default class HomeTimeline extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
hasUnread: PropTypes.bool,
|
|
||||||
hasFollows: PropTypes.bool,
|
hasFollows: PropTypes.bool,
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePin = () => {
|
|
||||||
const { columnId, dispatch } = this.props;
|
|
||||||
|
|
||||||
if (columnId) {
|
|
||||||
dispatch(removeColumn(columnId));
|
|
||||||
} else {
|
|
||||||
dispatch(addColumn('HOME', {}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMove = (dir) => {
|
|
||||||
const { columnId, dispatch } = this.props;
|
|
||||||
dispatch(moveColumn(columnId, dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
handleHeaderClick = () => {
|
|
||||||
this.column.scrollTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
setRef = c => {
|
|
||||||
this.column = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = () => {
|
|
||||||
this.props.dispatch(expandHomeTimeline());
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, hasUnread, hasFollows, columnId, multiColumn } = this.props;
|
const { intl, hasFollows, columnId, multiColumn } = this.props;
|
||||||
const pinned = !!columnId;
|
|
||||||
|
|
||||||
let emptyMessage;
|
let emptyMessage;
|
||||||
|
|
||||||
|
@ -72,28 +38,18 @@ export default class HomeTimeline extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column ref={this.setRef}>
|
<Timeline
|
||||||
<ColumnHeader
|
expand={expandHomeTimeline}
|
||||||
icon='home'
|
columnName='HOME'
|
||||||
active={hasUnread}
|
columnId={columnId}
|
||||||
title={intl.formatMessage(messages.title)}
|
mulitColumn={multiColumn}
|
||||||
onPin={this.handlePin}
|
emptyMessage={emptyMessage}
|
||||||
onMove={this.handleMove}
|
icon='home'
|
||||||
onClick={this.handleHeaderClick}
|
title={intl.formatMessage(messages.title)}
|
||||||
pinned={pinned}
|
settings={<ColumnSettingsContainer />}
|
||||||
multiColumn={multiColumn}
|
scrollName='home_timeline'
|
||||||
>
|
timelineId='home'
|
||||||
<ColumnSettingsContainer />
|
/>
|
||||||
</ColumnHeader>
|
|
||||||
|
|
||||||
<StatusListContainer
|
|
||||||
trackScroll={!pinned}
|
|
||||||
scrollKey={`home_timeline-${columnId}`}
|
|
||||||
loadMore={this.handleLoadMore}
|
|
||||||
timelineId='home'
|
|
||||||
emptyMessage={emptyMessage}
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,144 +1,44 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import StatusListContainer from '../ui/containers/status_list_container';
|
|
||||||
import Column from '../../components/column';
|
|
||||||
import ColumnHeader from '../../components/column_header';
|
|
||||||
import {
|
import {
|
||||||
refreshPublicTimeline,
|
refreshPublicTimeline,
|
||||||
expandPublicTimeline,
|
expandPublicTimeline,
|
||||||
updateTimeline,
|
|
||||||
deleteFromTimelines,
|
|
||||||
connectTimeline,
|
|
||||||
disconnectTimeline,
|
|
||||||
} from '../../actions/timelines';
|
} from '../../actions/timelines';
|
||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||||
import createStream from '../../stream';
|
import Timeline from '../timeline';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'column.public', defaultMessage: 'Federated timeline' },
|
title: { id: 'column.public', defaultMessage: 'Federated timeline' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
hasUnread: state.getIn(['timelines', 'public', 'unread']) > 0,
|
|
||||||
streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']),
|
|
||||||
accessToken: state.getIn(['meta', 'access_token']),
|
|
||||||
});
|
|
||||||
|
|
||||||
@connect(mapStateToProps)
|
|
||||||
@injectIntl
|
@injectIntl
|
||||||
export default class PublicTimeline extends React.PureComponent {
|
export default class PublicTimeline extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
streamingAPIBaseURL: PropTypes.string.isRequired,
|
|
||||||
accessToken: PropTypes.string.isRequired,
|
|
||||||
hasUnread: PropTypes.bool,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePin = () => {
|
|
||||||
const { columnId, dispatch } = this.props;
|
|
||||||
|
|
||||||
if (columnId) {
|
|
||||||
dispatch(removeColumn(columnId));
|
|
||||||
} else {
|
|
||||||
dispatch(addColumn('PUBLIC', {}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMove = (dir) => {
|
|
||||||
const { columnId, dispatch } = this.props;
|
|
||||||
dispatch(moveColumn(columnId, dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
handleHeaderClick = () => {
|
|
||||||
this.column.scrollTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
const { dispatch, streamingAPIBaseURL, accessToken } = this.props;
|
|
||||||
|
|
||||||
dispatch(refreshPublicTimeline());
|
|
||||||
|
|
||||||
if (typeof this._subscription !== 'undefined') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._subscription = createStream(streamingAPIBaseURL, accessToken, 'public', {
|
|
||||||
|
|
||||||
connected () {
|
|
||||||
dispatch(connectTimeline('public'));
|
|
||||||
},
|
|
||||||
|
|
||||||
reconnected () {
|
|
||||||
dispatch(connectTimeline('public'));
|
|
||||||
},
|
|
||||||
|
|
||||||
disconnected () {
|
|
||||||
dispatch(disconnectTimeline('public'));
|
|
||||||
},
|
|
||||||
|
|
||||||
received (data) {
|
|
||||||
switch(data.event) {
|
|
||||||
case 'update':
|
|
||||||
dispatch(updateTimeline('public', JSON.parse(data.payload)));
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
dispatch(deleteFromTimelines(data.payload));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount () {
|
|
||||||
if (typeof this._subscription !== 'undefined') {
|
|
||||||
this._subscription.close();
|
|
||||||
this._subscription = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setRef = c => {
|
|
||||||
this.column = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = () => {
|
|
||||||
this.props.dispatch(expandPublicTimeline());
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, columnId, hasUnread, multiColumn } = this.props;
|
const { intl, columnId, multiColumn } = this.props;
|
||||||
const pinned = !!columnId;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column ref={this.setRef}>
|
<Timeline
|
||||||
<ColumnHeader
|
expand={expandPublicTimeline}
|
||||||
icon='globe'
|
refresh={refreshPublicTimeline}
|
||||||
active={hasUnread}
|
streamId='public'
|
||||||
title={intl.formatMessage(messages.title)}
|
columnName='PUBLIC'
|
||||||
onPin={this.handlePin}
|
columnId={columnId}
|
||||||
onMove={this.handleMove}
|
mulitColumn={multiColumn}
|
||||||
onClick={this.handleHeaderClick}
|
emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other instances to fill it up' />}
|
||||||
pinned={pinned}
|
icon='globe'
|
||||||
multiColumn={multiColumn}
|
title={intl.formatMessage(messages.title)}
|
||||||
>
|
settings={<ColumnSettingsContainer />}
|
||||||
<ColumnSettingsContainer />
|
scrollName='public_timeline'
|
||||||
</ColumnHeader>
|
timelineId='public'
|
||||||
|
/>
|
||||||
<StatusListContainer
|
|
||||||
timelineId='public'
|
|
||||||
loadMore={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 instances to fill it up' />}
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import StatusListContainer from '../ui/containers/status_list_container';
|
||||||
|
import Column from '../../components/column';
|
||||||
|
import ColumnHeader from '../../components/column_header';
|
||||||
|
import {
|
||||||
|
updateTimeline,
|
||||||
|
deleteFromTimelines,
|
||||||
|
connectTimeline,
|
||||||
|
disconnectTimeline,
|
||||||
|
} from '../../actions/timelines';
|
||||||
|
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||||
|
import createStream from '../../stream';
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownprops) => ({
|
||||||
|
streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']),
|
||||||
|
accessToken: state.getIn(['meta', 'access_token']),
|
||||||
|
hasUnread: state.getIn(['timelines', ownprops.timelineId, 'unread']) > 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
@connect(mapStateToProps)
|
||||||
|
export default class Timeline extends React.PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
streamingAPIBaseURL: PropTypes.string.isRequired,
|
||||||
|
accessToken: PropTypes.string.isRequired,
|
||||||
|
expand: PropTypes.func.isRequired,
|
||||||
|
refresh: PropTypes.func,
|
||||||
|
streamId: PropTypes.string,
|
||||||
|
hasUnread: PropTypes.bool,
|
||||||
|
columnName: PropTypes.string.isRequired,
|
||||||
|
columnProps: PropTypes.object,
|
||||||
|
columnId: PropTypes.string,
|
||||||
|
multiColumn: PropTypes.bool,
|
||||||
|
emptyMessage: PropTypes.oneOfType([
|
||||||
|
PropTypes.element,
|
||||||
|
PropTypes.string,
|
||||||
|
]),
|
||||||
|
icon: PropTypes.string.isRequired,
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
settings: PropTypes.element,
|
||||||
|
scrollName: PropTypes.string.isRequired,
|
||||||
|
timelineId: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
handlePin = () => {
|
||||||
|
const { columnName, columnProps, columnId, dispatch } = this.props;
|
||||||
|
|
||||||
|
if (columnId) {
|
||||||
|
dispatch(removeColumn(columnId));
|
||||||
|
} else {
|
||||||
|
dispatch(addColumn(columnName, columnProps || {}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMove = (dir) => {
|
||||||
|
const { columnId, dispatch } = this.props;
|
||||||
|
dispatch(moveColumn(columnId, dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleHeaderClick = () => {
|
||||||
|
this.column.scrollTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
setRef = c => {
|
||||||
|
this.column = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLoadMore = () => {
|
||||||
|
this.props.dispatch(this.props.expand());
|
||||||
|
}
|
||||||
|
|
||||||
|
_subscribe (dispatch, streamId, timelineId) {
|
||||||
|
const { streamingAPIBaseURL, accessToken } = this.props;
|
||||||
|
|
||||||
|
if (!streamId || !timelineId) return;
|
||||||
|
|
||||||
|
this.subscription = createStream(streamingAPIBaseURL, accessToken, streamId, {
|
||||||
|
|
||||||
|
connected () {
|
||||||
|
dispatch(connectTimeline(timelineId));
|
||||||
|
},
|
||||||
|
|
||||||
|
reconnected () {
|
||||||
|
dispatch(connectTimeline(timelineId));
|
||||||
|
},
|
||||||
|
|
||||||
|
disconnected () {
|
||||||
|
dispatch(disconnectTimeline(timelineId));
|
||||||
|
},
|
||||||
|
|
||||||
|
received (data) {
|
||||||
|
switch(data.event) {
|
||||||
|
case 'update':
|
||||||
|
dispatch(updateTimeline(timelineId, JSON.parse(data.payload)));
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
dispatch(deleteFromTimelines(data.payload));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_unsubscribe () {
|
||||||
|
if (typeof this.subscription !== 'undefined') {
|
||||||
|
this.subscription.close();
|
||||||
|
this.subscription = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
const { dispatch, refresh, streamId, timelineId } = this.props;
|
||||||
|
|
||||||
|
if (typeof refresh !== 'function') return;
|
||||||
|
|
||||||
|
dispatch(refresh());
|
||||||
|
this._subscribe(dispatch, streamId, timelineId);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
if (nextProps.streamId !== this.props.streamId || nextProps.timelineId !== this.props.timelineId) {
|
||||||
|
|
||||||
|
if (typeof refresh !== 'function') return;
|
||||||
|
|
||||||
|
this.props.dispatch(this.props.refresh());
|
||||||
|
this._unsubscribe();
|
||||||
|
this._subscribe(this.props.dispatch, nextProps.streamId, nextProps.timelineId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
this._unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {
|
||||||
|
hasUnread,
|
||||||
|
columnId,
|
||||||
|
multiColumn,
|
||||||
|
emptyMessage,
|
||||||
|
icon,
|
||||||
|
title,
|
||||||
|
settings,
|
||||||
|
scrollName,
|
||||||
|
timelineId,
|
||||||
|
} = this.props;
|
||||||
|
const pinned = !!columnId;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column ref={this.setRef}>
|
||||||
|
<ColumnHeader
|
||||||
|
icon={icon}
|
||||||
|
active={hasUnread}
|
||||||
|
title={title}
|
||||||
|
onPin={this.handlePin}
|
||||||
|
onMove={this.handleMove}
|
||||||
|
onClick={this.handleHeaderClick}
|
||||||
|
pinned={pinned}
|
||||||
|
multiColumn={multiColumn}
|
||||||
|
>
|
||||||
|
{settings}
|
||||||
|
</ColumnHeader>
|
||||||
|
|
||||||
|
<StatusListContainer
|
||||||
|
trackScroll={!pinned}
|
||||||
|
scrollKey={`${scrollName}-${columnId}`}
|
||||||
|
loadMore={this.handleLoadMore}
|
||||||
|
timelineId={timelineId}
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue