* Do not push DMs into the home feed * Show DMs column after sending a DM, if DMs column is not already shownmaster
@@ -56,7 +56,7 @@ export function changeCompose(text) { | |||
}; | |||
}; | |||
export function replyCompose(status, router) { | |||
export function replyCompose(status, routerHistory) { | |||
return (dispatch, getState) => { | |||
dispatch({ | |||
type: COMPOSE_REPLY, | |||
@@ -64,7 +64,7 @@ export function replyCompose(status, router) { | |||
}); | |||
if (!getState().getIn(['compose', 'mounted'])) { | |||
router.push('/statuses/new'); | |||
routerHistory.push('/statuses/new'); | |||
} | |||
}; | |||
}; | |||
@@ -81,7 +81,7 @@ export function resetCompose() { | |||
}; | |||
}; | |||
export function mentionCompose(account, router) { | |||
export function mentionCompose(account, routerHistory) { | |||
return (dispatch, getState) => { | |||
dispatch({ | |||
type: COMPOSE_MENTION, | |||
@@ -89,12 +89,12 @@ export function mentionCompose(account, router) { | |||
}); | |||
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, | |||
@@ -102,12 +102,12 @@ export function directCompose(account, router) { | |||
}); | |||
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']); | |||
@@ -133,21 +133,22 @@ export function submitCompose() { | |||
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)); | |||
@@ -5,11 +5,22 @@ import { | |||
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()); | |||
@@ -30,6 +30,10 @@ const messages = defineMessages({ | |||
export default @injectIntl | |||
class ComposeForm extends ImmutablePureComponent { | |||
static contextTypes = { | |||
router: PropTypes.object, | |||
}; | |||
static propTypes = { | |||
intl: PropTypes.object.isRequired, | |||
text: PropTypes.string.isRequired, | |||
@@ -84,7 +88,7 @@ class ComposeForm extends ImmutablePureComponent { | |||
return; | |||
} | |||
this.props.onSubmit(); | |||
this.props.onSubmit(this.context.router.history); | |||
} | |||
onSuggestionsClearRequested = () => { | |||
@@ -14,6 +14,10 @@ const messages = defineMessages({ | |||
export default @injectIntl | |||
class Upload extends ImmutablePureComponent { | |||
static contextTypes = { | |||
router: PropTypes.object, | |||
}; | |||
static propTypes = { | |||
media: ImmutablePropTypes.map.isRequired, | |||
intl: PropTypes.object.isRequired, | |||
@@ -37,7 +41,7 @@ class Upload extends ImmutablePureComponent { | |||
handleSubmit = () => { | |||
this.handleInputBlur(); | |||
this.props.onSubmit(); | |||
this.props.onSubmit(this.context.router.history); | |||
} | |||
handleUndoClick = () => { | |||
@@ -33,8 +33,8 @@ const mapDispatchToProps = (dispatch) => ({ | |||
dispatch(changeCompose(text)); | |||
}, | |||
onSubmit () { | |||
dispatch(submitCompose()); | |||
onSubmit (router) { | |||
dispatch(submitCompose(router)); | |||
}, | |||
onClearSuggestions () { | |||
@@ -22,8 +22,8 @@ const mapDispatchToProps = dispatch => ({ | |||
dispatch(openModal('FOCAL_POINT', { id })); | |||
}, | |||
onSubmit () { | |||
dispatch(submitCompose()); | |||
onSubmit (router) { | |||
dispatch(submitCompose(router)); | |||
}, | |||
}); | |||
@@ -3,7 +3,7 @@ import { connect } from 'react-redux'; | |||
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'; | |||
@@ -48,11 +48,14 @@ class DirectTimeline extends React.PureComponent { | |||
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; | |||
@@ -1,5 +1,7 @@ | |||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; | |||
import { | |||
CONVERSATIONS_MOUNT, | |||
CONVERSATIONS_UNMOUNT, | |||
CONVERSATIONS_FETCH_REQUEST, | |||
CONVERSATIONS_FETCH_SUCCESS, | |||
CONVERSATIONS_FETCH_FAIL, | |||
@@ -11,6 +13,7 @@ const initialState = ImmutableMap({ | |||
items: ImmutableList(), | |||
isLoading: false, | |||
hasMore: true, | |||
mounted: false, | |||
}); | |||
const conversationToMap = item => ImmutableMap({ | |||
@@ -73,6 +76,10 @@ export default function conversations(state = initialState, action) { | |||
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; | |||
} | |||
@@ -39,7 +39,6 @@ class BatchedRemoveStatusService < BaseService | |||
# 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 | |||
@@ -96,16 +95,6 @@ class BatchedRemoveStatusService < BaseService | |||
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? | |||
@@ -6,15 +6,12 @@ class FanOutOnWriteService < BaseService | |||
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 | |||
@@ -56,16 +53,6 @@ class FanOutOnWriteService < BaseService | |||
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) | |||
@@ -94,16 +81,6 @@ class FanOutOnWriteService < BaseService | |||
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 | |||
@@ -21,7 +21,6 @@ class RemoveStatusService < BaseService | |||
remove_from_hashtags | |||
remove_from_public | |||
remove_from_media if status.media_attachments.any? | |||
remove_from_direct if status.direct_visibility? | |||
@status.destroy! | |||
@@ -153,13 +152,6 @@ class RemoveStatusService < BaseService | |||
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 | |||