diff --git a/app/soapbox/actions/streaming.js b/app/soapbox/actions/streaming.js index 3b66a0472..1baa252b0 100644 --- a/app/soapbox/actions/streaming.js +++ b/app/soapbox/actions/streaming.js @@ -82,7 +82,8 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => { export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification); export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`); export const connectPublicStream = ({ onlyMedia } = {}) => connectTimelineStream(`public${onlyMedia ? ':media' : ''}`, `public${onlyMedia ? ':media' : ''}`); +export const connectRemoteStream = (instance, { onlyMedia } = {}) => connectTimelineStream(`remote${onlyMedia ? ':media' : ''}:${instance}`, `public:remote${onlyMedia ? ':media' : ''}&instance=${instance}`); export const connectHashtagStream = (id, tag, accept) => connectTimelineStream(`hashtag:${id}`, `hashtag&tag=${tag}`, null, accept); export const connectDirectStream = () => connectTimelineStream('direct', 'direct'); export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`); -export const connectGroupStream = id => connectTimelineStream(`group:${id}`, `group&group=${id}`); +export const connectGroupStream = id => connectTimelineStream(`group:${id}`, `group&group=${id}`); diff --git a/app/soapbox/actions/timelines.js b/app/soapbox/actions/timelines.js index 67f6b19f8..7ce6320fd 100644 --- a/app/soapbox/actions/timelines.js +++ b/app/soapbox/actions/timelines.js @@ -166,6 +166,8 @@ export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => ex export const expandPublicTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`public${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { max_id: maxId, only_media: !!onlyMedia }, done); +export const expandRemoteTimeline = (instance, { maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`remote${onlyMedia ? ':media' : ''}:${instance}`, '/api/v1/timelines/public', { local: false, instance: instance, max_id: maxId, only_media: !!onlyMedia }, done); + export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done); export const expandDirectTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('direct', '/api/v1/timelines/direct', { max_id: maxId }, done); diff --git a/app/soapbox/components/status.js b/app/soapbox/components/status.js index c93ccac22..175d6a0e4 100644 --- a/app/soapbox/components/status.js +++ b/app/soapbox/components/status.js @@ -17,7 +17,7 @@ import { HotKeys } from 'react-hotkeys'; import classNames from 'classnames'; import Icon from 'soapbox/components/icon'; import PollContainer from 'soapbox/containers/poll_container'; -import { NavLink } from 'react-router-dom'; +import { Link, NavLink } from 'react-router-dom'; import { getDomain } from 'soapbox/utils/accounts'; import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper'; @@ -459,7 +459,9 @@ class Status extends ImmutablePureComponent { {favicon &&
- + + +
}
diff --git a/app/soapbox/features/remote_timeline/index.js b/app/soapbox/features/remote_timeline/index.js new file mode 100644 index 000000000..ee08192ff --- /dev/null +++ b/app/soapbox/features/remote_timeline/index.js @@ -0,0 +1,111 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import PropTypes from 'prop-types'; +import StatusListContainer from '../ui/containers/status_list_container'; +import Column from '../../components/column'; +import HomeColumnHeader from '../../components/home_column_header'; +import IconButton from 'soapbox/components/icon_button'; +import { expandRemoteTimeline } from '../../actions/timelines'; +import { connectRemoteStream } from '../../actions/streaming'; +import { getSettings } from 'soapbox/actions/settings'; + +const messages = defineMessages({ + title: { id: 'column.remote', defaultMessage: 'Federated timeline' }, +}); + +const mapStateToProps = (state, props) => { + const instance = props.params.instance; + const settings = getSettings(state); + const onlyMedia = settings.getIn(['remote', 'other', 'onlyMedia']); + + const timelineId = 'remote'; + + return { + timelineId, + onlyMedia, + hasUnread: state.getIn(['timelines', `${timelineId}${onlyMedia ? ':media' : ''}:${instance}`, 'unread']) > 0, + instance, + }; +}; + +export default @connect(mapStateToProps) +@injectIntl +class RemoteTimeline extends React.PureComponent { + + static contextTypes = { + router: PropTypes.object, + }; + + static propTypes = { + dispatch: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, + hasUnread: PropTypes.bool, + onlyMedia: PropTypes.bool, + timelineId: PropTypes.string, + instance: PropTypes.string.isRequired, + }; + + componentDidMount() { + const { dispatch, onlyMedia, instance } = this.props; + dispatch(expandRemoteTimeline(instance, { onlyMedia })); + this.disconnect = dispatch(connectRemoteStream(instance, { onlyMedia })); + } + + componentDidUpdate(prevProps) { + if (prevProps.onlyMedia !== this.props.onlyMedia) { + const { dispatch, onlyMedia, instance } = this.props; + this.disconnect(); + + dispatch(expandRemoteTimeline(instance, { onlyMedia })); + this.disconnect = dispatch(connectRemoteStream(instance, { onlyMedia })); + } + } + + componentWillUnmount() { + if (this.disconnect) { + this.disconnect(); + this.disconnect = null; + } + } + + handleCloseClick = e => { + this.context.router.history.push('/timeline/fediverse'); + } + + handleLoadMore = maxId => { + const { dispatch, onlyMedia, instance } = this.props; + dispatch(expandRemoteTimeline(instance, { maxId, onlyMedia })); + } + + render() { + const { intl, hasUnread, onlyMedia, timelineId, instance } = this.props; + + return ( + + +
+ + +
+ + } + /> +
+ ); + } + +} diff --git a/app/soapbox/features/status/components/detailed_status.js b/app/soapbox/features/status/components/detailed_status.js index ee162810e..6f8608d5e 100644 --- a/app/soapbox/features/status/components/detailed_status.js +++ b/app/soapbox/features/status/components/detailed_status.js @@ -5,7 +5,7 @@ import Avatar from '../../../components/avatar'; import DisplayName from '../../../components/display_name'; import StatusContent from '../../../components/status_content'; import MediaGallery from '../../../components/media_gallery'; -import { NavLink } from 'react-router-dom'; +import { Link, NavLink } from 'react-router-dom'; import { FormattedDate } from 'react-intl'; import Card from './card'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -197,7 +197,9 @@ export default class DetailedStatus extends ImmutablePureComponent {
{favicon &&
- + + +
} {statusTypeIcon} diff --git a/app/soapbox/features/ui/index.js b/app/soapbox/features/ui/index.js index 9f0085772..8b714fe7e 100644 --- a/app/soapbox/features/ui/index.js +++ b/app/soapbox/features/ui/index.js @@ -45,6 +45,7 @@ import { // GettingStarted, CommunityTimeline, PublicTimeline, + RemoteTimeline, AccountTimeline, AccountGallery, HomeTimeline, @@ -208,6 +209,7 @@ class SwitchingColumnsArea extends React.PureComponent { + {/* diff --git a/app/soapbox/features/ui/util/async-components.js b/app/soapbox/features/ui/util/async-components.js index 01838b156..3cb9e5142 100644 --- a/app/soapbox/features/ui/util/async-components.js +++ b/app/soapbox/features/ui/util/async-components.js @@ -18,6 +18,10 @@ export function PublicTimeline() { return import(/* webpackChunkName: "features/public_timeline" */'../../public_timeline'); } +export function RemoteTimeline() { + return import(/* webpackChunkName: "features/remote_timeline" */'../../remote_timeline'); +} + export function CommunityTimeline() { return import(/* webpackChunkName: "features/community_timeline" */'../../community_timeline'); } diff --git a/app/styles/components/columns.scss b/app/styles/components/columns.scss index a3f2dac95..a2f430538 100644 --- a/app/styles/components/columns.scss +++ b/app/styles/components/columns.scss @@ -716,3 +716,13 @@ color: white; } } + +.timeline-filter-message { + background-color: var(--brand-color--faint); + color: var(--primary-text-color); + padding: 15px 20px; + + .icon-button { + margin-right: 8px; + } +}