};
};
-export function replyCompose(status, router) {
+export function replyCompose(status, routerHistory) {
return (dispatch, getState) => {
dispatch({
type: COMPOSE_REPLY,
});
if (!getState().getIn(['compose', 'mounted'])) {
- router.push('/statuses/new');
+ routerHistory.push('/statuses/new');
}
};
};
};
};
-export function mentionCompose(account, router) {
+export function mentionCompose(account, routerHistory) {
return (dispatch, getState) => {
dispatch({
type: COMPOSE_MENTION,
});
if (!getState().getIn(['compose', 'mounted'])) {
- router.push('/statuses/new');
+ routerHistory.push('/statuses/new');
}
};
};
-export function directCompose(account, router) {
+export function directCompose(account, routerHistory) {
return (dispatch, getState) => {
dispatch({
type: COMPOSE_DIRECT,
});
if (!getState().getIn(['compose', 'mounted'])) {
- router.push('/statuses/new');
+ routerHistory.push('/statuses/new');
}
};
};
-export function submitCompose() {
+export function submitCompose(routerHistory) {
return function (dispatch, getState) {
const status = getState().getIn(['compose', 'text'], '');
const media = getState().getIn(['compose', 'media_attachments']);
dispatch(insertIntoTagHistory(response.data.tags, status));
dispatch(submitComposeSuccess({ ...response.data }));
- // To make the app more responsive, immediately get the status into the columns
+ // To make the app more responsive, immediately push the status
+ // into the columns
- const insertIfOnline = (timelineId) => {
+ const insertIfOnline = timelineId => {
if (getState().getIn(['timelines', timelineId, 'items', 0]) !== null) {
dispatch(updateTimeline(timelineId, { ...response.data }));
}
};
- insertIfOnline('home');
-
- if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
+ if (response.data.visibility === 'direct' && getState().getIn(['conversations', 'mounted']) <= 0) {
+ routerHistory.push('/timelines/direct');
+ } else if (response.data.visibility !== 'direct') {
+ insertIfOnline('home');
+ } else if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
insertIfOnline('community');
insertIfOnline('public');
- } else if (response.data.visibility === 'direct') {
- insertIfOnline('direct');
}
}).catch(function (error) {
dispatch(submitComposeFail(error));
importFetchedStatus,
} from './importer';
+export const CONVERSATIONS_MOUNT = 'CONVERSATIONS_MOUNT';
+export const CONVERSATIONS_UNMOUNT = 'CONVERSATIONS_UNMOUNT';
+
export const CONVERSATIONS_FETCH_REQUEST = 'CONVERSATIONS_FETCH_REQUEST';
export const CONVERSATIONS_FETCH_SUCCESS = 'CONVERSATIONS_FETCH_SUCCESS';
export const CONVERSATIONS_FETCH_FAIL = 'CONVERSATIONS_FETCH_FAIL';
export const CONVERSATIONS_UPDATE = 'CONVERSATIONS_UPDATE';
+export const mountConversations = () => ({
+ type: CONVERSATIONS_MOUNT,
+});
+
+export const unmountConversations = () => ({
+ type: CONVERSATIONS_UNMOUNT,
+});
+
export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => {
dispatch(expandConversationsRequest());
export default @injectIntl
class ComposeForm extends ImmutablePureComponent {
+ static contextTypes = {
+ router: PropTypes.object,
+ };
+
static propTypes = {
intl: PropTypes.object.isRequired,
text: PropTypes.string.isRequired,
return;
}
- this.props.onSubmit();
+ this.props.onSubmit(this.context.router.history);
}
onSuggestionsClearRequested = () => {
export default @injectIntl
class Upload extends ImmutablePureComponent {
+ static contextTypes = {
+ router: PropTypes.object,
+ };
+
static propTypes = {
media: ImmutablePropTypes.map.isRequired,
intl: PropTypes.object.isRequired,
handleSubmit = () => {
this.handleInputBlur();
- this.props.onSubmit();
+ this.props.onSubmit(this.context.router.history);
}
handleUndoClick = () => {
dispatch(changeCompose(text));
},
- onSubmit () {
- dispatch(submitCompose());
+ onSubmit (router) {
+ dispatch(submitCompose(router));
},
onClearSuggestions () {
dispatch(openModal('FOCAL_POINT', { id }));
},
- onSubmit () {
- dispatch(submitCompose());
+ onSubmit (router) {
+ dispatch(submitCompose(router));
},
});
import PropTypes from 'prop-types';
import Column from '../../components/column';
import ColumnHeader from '../../components/column_header';
-import { expandConversations } from '../../actions/conversations';
+import { mountConversations, unmountConversations, expandConversations } from '../../actions/conversations';
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { connectDirectStream } from '../../actions/streaming';
componentDidMount () {
const { dispatch } = this.props;
+ dispatch(mountConversations());
dispatch(expandConversations());
this.disconnect = dispatch(connectDirectStream());
}
componentWillUnmount () {
+ this.props.dispatch(unmountConversations());
+
if (this.disconnect) {
this.disconnect();
this.disconnect = null;
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import {
+ CONVERSATIONS_MOUNT,
+ CONVERSATIONS_UNMOUNT,
CONVERSATIONS_FETCH_REQUEST,
CONVERSATIONS_FETCH_SUCCESS,
CONVERSATIONS_FETCH_FAIL,
items: ImmutableList(),
isLoading: false,
hasMore: true,
+ mounted: false,
});
const conversationToMap = item => ImmutableMap({
return expandNormalizedConversations(state, action.conversations, action.next);
case CONVERSATIONS_UPDATE:
return updateConversation(state, action.conversation);
+ case CONVERSATIONS_MOUNT:
+ return state.update('mounted', count => count + 1);
+ case CONVERSATIONS_UNMOUNT:
+ return state.update('mounted', count => count - 1);
default:
return state;
}
# Cannot be batched
statuses.each do |status|
unpush_from_public_timelines(status)
- unpush_from_direct_timelines(status) if status.direct_visibility?
batch_salmon_slaps(status) if status.local?
end
end
end
- def unpush_from_direct_timelines(status)
- payload = @json_payloads[status.id]
- redis.pipelined do
- @mentions[status.id].each do |mention|
- redis.publish("timeline:direct:#{mention.account.id}", payload) if mention.account.local?
- end
- redis.publish("timeline:direct:#{status.account.id}", payload) if status.account.local?
- end
- end
-
def batch_salmon_slaps(status)
return if @mentions[status.id].empty?
def call(status)
raise Mastodon::RaceConditionError if status.visibility.nil?
- deliver_to_self(status) if status.account.local?
-
render_anonymous_payload(status)
if status.direct_visibility?
- deliver_to_mentioned_followers(status)
- deliver_to_direct_timelines(status)
deliver_to_own_conversation(status)
else
+ deliver_to_self(status) if status.account.local?
deliver_to_followers(status)
deliver_to_lists(status)
end
end
end
- def deliver_to_mentioned_followers(status)
- Rails.logger.debug "Delivering status #{status.id} to mentioned followers"
-
- status.mentions.includes(:account).each do |mention|
- mentioned_account = mention.account
- next if !mentioned_account.local? || !mentioned_account.following?(status.account) || FeedManager.instance.filter?(:home, status, mention.account_id)
- FeedManager.instance.push_to_home(mentioned_account, status)
- end
- end
-
def render_anonymous_payload(status)
@payload = InlineRenderer.render(status, nil, :status)
@payload = Oj.dump(event: :update, payload: @payload)
Redis.current.publish('timeline:public:local:media', @payload) if status.local?
end
- def deliver_to_direct_timelines(status)
- Rails.logger.debug "Delivering status #{status.id} to direct timelines"
-
- status.mentions.includes(:account).each do |mention|
- Redis.current.publish("timeline:direct:#{mention.account.id}", @payload) if mention.account.local?
- end
-
- Redis.current.publish("timeline:direct:#{status.account.id}", @payload) if status.account.local?
- end
-
def deliver_to_own_conversation(status)
AccountConversation.add_status(status.account, status)
end
remove_from_hashtags
remove_from_public
remove_from_media if status.media_attachments.any?
- remove_from_direct if status.direct_visibility?
@status.destroy!
Redis.current.publish('timeline:public:local:media', @payload) if @status.local?
end
- def remove_from_direct
- @mentions.each do |mention|
- Redis.current.publish("timeline:direct:#{mention.account.id}", @payload) if mention.account.local?
- end
- Redis.current.publish("timeline:direct:#{@account.id}", @payload) if @account.local?
- end
-
def redis
Redis.current
end