* Add compacted component * 引用表示の間にコンテナをはさみ、不要なコードを削除 * 引用APIを作成、ついでにブロック状況を引用APIに反映 * テスト修正など * 引用をキャッシュに登録 * `quote_id`が`quote_of_id`になったのをSerializerに反映 * Fix test * 引用をフィルターの対象に含める設定+エラー修正 * ストリーミングの存在しないプロパティ削除によるエラーを修正 * Fix lint * 他のサーバーから来た引用付き投稿を処理 * Fix test * フィルター設定時エラーの調整 * 画像つき投稿のスタイルを調整 * 画像つき投稿の最大高さを調整 * 引用禁止・非表示の設定を追加 * ブロック対応 * マイグレーションコード調整 * 引用設定の翻訳を作成 * Lint修正 * 参照1つの場合は引用に変換する設定を削除 * 不要になったテストを削除 * ブロック設定追加、バグ修正 * 他サーバーへ引用送信・受け入れ
322 lines
9.1 KiB
JavaScript
322 lines
9.1 KiB
JavaScript
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import {
|
|
unmuteAccount,
|
|
unblockAccount,
|
|
} from '../actions/accounts';
|
|
import { showAlertForError } from '../actions/alerts';
|
|
import { initBlockModal } from '../actions/blocks';
|
|
import { initBoostModal } from '../actions/boosts';
|
|
import {
|
|
replyCompose,
|
|
mentionCompose,
|
|
directCompose,
|
|
insertReferenceCompose,
|
|
} from '../actions/compose';
|
|
import {
|
|
blockDomain,
|
|
unblockDomain,
|
|
} from '../actions/domain_blocks';
|
|
import {
|
|
initAddFilter,
|
|
} from '../actions/filters';
|
|
import {
|
|
reblog,
|
|
favourite,
|
|
emojiReact,
|
|
bookmark,
|
|
unreblog,
|
|
unfavourite,
|
|
unEmojiReact,
|
|
unbookmark,
|
|
pin,
|
|
unpin,
|
|
} from '../actions/interactions';
|
|
import { openModal } from '../actions/modal';
|
|
import { initMuteModal } from '../actions/mutes';
|
|
import { deployPictureInPicture } from '../actions/picture_in_picture';
|
|
import { initReport } from '../actions/reports';
|
|
import {
|
|
muteStatus,
|
|
unmuteStatus,
|
|
deleteStatus,
|
|
hideStatus,
|
|
revealStatus,
|
|
toggleStatusCollapse,
|
|
editStatus,
|
|
translateStatus,
|
|
undoStatusTranslation,
|
|
} from '../actions/statuses';
|
|
import Status from '../components/status';
|
|
import { boostModal, deleteModal } from '../initial_state';
|
|
import { makeGetStatus, makeGetPictureInPicture } from '../selectors';
|
|
|
|
const messages = defineMessages({
|
|
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
|
|
deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
|
|
redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
|
|
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.' },
|
|
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
|
|
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
|
editConfirm: { id: 'confirmations.edit.confirm', defaultMessage: 'Edit' },
|
|
editMessage: { id: 'confirmations.edit.message', defaultMessage: 'Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
|
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Block entire domain' },
|
|
});
|
|
|
|
const makeMapStateToProps = () => {
|
|
const getStatus = makeGetStatus();
|
|
const getPictureInPicture = makeGetPictureInPicture();
|
|
|
|
const mapStateToProps = (state, props) => ({
|
|
status: getStatus(state, props),
|
|
nextInReplyToId: props.nextId ? state.getIn(['statuses', props.nextId, 'in_reply_to_id']) : null,
|
|
pictureInPicture: getPictureInPicture(state, props),
|
|
});
|
|
|
|
return mapStateToProps;
|
|
};
|
|
|
|
const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
|
|
|
|
contextType,
|
|
|
|
onReply (status, router) {
|
|
dispatch((_, getState) => {
|
|
let state = getState();
|
|
|
|
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
|
dispatch(openModal({
|
|
modalType: 'CONFIRM',
|
|
modalProps: {
|
|
message: intl.formatMessage(messages.replyMessage),
|
|
confirm: intl.formatMessage(messages.replyConfirm),
|
|
onConfirm: () => dispatch(replyCompose(status, router)) },
|
|
}));
|
|
} else {
|
|
dispatch(replyCompose(status, router));
|
|
}
|
|
});
|
|
},
|
|
|
|
onModalReblog (status, privacy) {
|
|
if (status.get('reblogged')) {
|
|
dispatch(unreblog(status));
|
|
} else {
|
|
dispatch(reblog(status, privacy));
|
|
}
|
|
},
|
|
|
|
onReblog (status, e) {
|
|
if ((e && e.shiftKey) || !boostModal) {
|
|
this.onModalReblog(status);
|
|
} else {
|
|
dispatch(initBoostModal({ status, onReblog: this.onModalReblog }));
|
|
}
|
|
},
|
|
|
|
onReblogForceModal (status) {
|
|
dispatch(initBoostModal({ status, onReblog: this.onModalReblog }));
|
|
},
|
|
|
|
onFavourite (status) {
|
|
if (status.get('favourited')) {
|
|
dispatch(unfavourite(status));
|
|
} else {
|
|
dispatch(favourite(status));
|
|
}
|
|
},
|
|
|
|
onEmojiReact (status, emoji) {
|
|
dispatch(emojiReact(status, emoji));
|
|
},
|
|
|
|
onUnEmojiReact (status, emoji) {
|
|
dispatch(unEmojiReact(status, emoji));
|
|
},
|
|
|
|
onBookmark (status) {
|
|
if (status.get('bookmarked')) {
|
|
dispatch(unbookmark(status));
|
|
} else {
|
|
dispatch(bookmark(status));
|
|
}
|
|
},
|
|
|
|
onBookmarkCategoryAdder (status) {
|
|
dispatch(openModal({
|
|
modalType: 'BOOKMARK_CATEGORY_ADDER',
|
|
modalProps: {
|
|
statusId: status.get('id'),
|
|
},
|
|
}));
|
|
},
|
|
|
|
onPin (status) {
|
|
if (status.get('pinned')) {
|
|
dispatch(unpin(status));
|
|
} else {
|
|
dispatch(pin(status));
|
|
}
|
|
},
|
|
|
|
onEmbed (status) {
|
|
dispatch(openModal({
|
|
modalType: 'EMBED',
|
|
modalProps: {
|
|
id: status.get('id'),
|
|
onError: error => dispatch(showAlertForError(error)),
|
|
},
|
|
}));
|
|
},
|
|
|
|
onDelete (status, history, withRedraft = false) {
|
|
if (!deleteModal) {
|
|
dispatch(deleteStatus(status.get('id'), history, withRedraft));
|
|
} else {
|
|
dispatch(openModal({
|
|
modalType: 'CONFIRM',
|
|
modalProps: {
|
|
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
|
|
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
|
|
onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),
|
|
},
|
|
}));
|
|
}
|
|
},
|
|
|
|
onEdit (status, history) {
|
|
dispatch((_, getState) => {
|
|
let state = getState();
|
|
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
|
dispatch(openModal({
|
|
modalType: 'CONFIRM',
|
|
modalProps: {
|
|
message: intl.formatMessage(messages.editMessage),
|
|
confirm: intl.formatMessage(messages.editConfirm),
|
|
onConfirm: () => dispatch(editStatus(status.get('id'), history)),
|
|
},
|
|
}));
|
|
} else {
|
|
dispatch(editStatus(status.get('id'), history));
|
|
}
|
|
});
|
|
},
|
|
|
|
onReference (status) {
|
|
dispatch(insertReferenceCompose(0, status.get('url'), 'BT'));
|
|
},
|
|
|
|
onQuote (status) {
|
|
dispatch(insertReferenceCompose(0, status.get('url'), 'QT'));
|
|
},
|
|
|
|
onTranslate (status) {
|
|
if (status.get('translation')) {
|
|
dispatch(undoStatusTranslation(status.get('id'), status.get('poll')));
|
|
} else {
|
|
dispatch(translateStatus(status.get('id')));
|
|
}
|
|
},
|
|
|
|
onDirect (account, router) {
|
|
dispatch(directCompose(account, router));
|
|
},
|
|
|
|
onMention (account, router) {
|
|
dispatch(mentionCompose(account, router));
|
|
},
|
|
|
|
onOpenMedia (statusId, media, index, lang) {
|
|
dispatch(openModal({
|
|
modalType: 'MEDIA',
|
|
modalProps: { statusId, media, index, lang },
|
|
}));
|
|
},
|
|
|
|
onOpenVideo (statusId, media, lang, options) {
|
|
dispatch(openModal({
|
|
modalType: 'VIDEO',
|
|
modalProps: { statusId, media, lang, options },
|
|
}));
|
|
},
|
|
|
|
onBlock (status) {
|
|
const account = status.get('account');
|
|
dispatch(initBlockModal(account));
|
|
},
|
|
|
|
onUnblock (account) {
|
|
dispatch(unblockAccount(account.get('id')));
|
|
},
|
|
|
|
onReport (status) {
|
|
dispatch(initReport(status.get('account'), status));
|
|
},
|
|
|
|
onAddFilter (status) {
|
|
dispatch(initAddFilter(status, { contextType }));
|
|
},
|
|
|
|
onMute (account) {
|
|
dispatch(initMuteModal(account));
|
|
},
|
|
|
|
onUnmute (account) {
|
|
dispatch(unmuteAccount(account.get('id')));
|
|
},
|
|
|
|
onMuteConversation (status) {
|
|
if (status.get('muted')) {
|
|
dispatch(unmuteStatus(status.get('id')));
|
|
} else {
|
|
dispatch(muteStatus(status.get('id')));
|
|
}
|
|
},
|
|
|
|
onToggleHidden (status) {
|
|
if (status.get('hidden')) {
|
|
dispatch(revealStatus(status.get('id')));
|
|
} else {
|
|
dispatch(hideStatus(status.get('id')));
|
|
}
|
|
},
|
|
|
|
onToggleCollapsed (status, isCollapsed) {
|
|
dispatch(toggleStatusCollapse(status.get('id'), isCollapsed));
|
|
},
|
|
|
|
onBlockDomain (domain) {
|
|
dispatch(openModal({
|
|
modalType: 'CONFIRM',
|
|
modalProps: {
|
|
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
|
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
|
onConfirm: () => dispatch(blockDomain(domain)),
|
|
},
|
|
}));
|
|
},
|
|
|
|
onUnblockDomain (domain) {
|
|
dispatch(unblockDomain(domain));
|
|
},
|
|
|
|
deployPictureInPicture (status, type, mediaProps) {
|
|
dispatch(deployPictureInPicture(status.get('id'), status.getIn(['account', 'id']), type, mediaProps));
|
|
},
|
|
|
|
onInteractionModal (type, status) {
|
|
dispatch(openModal({
|
|
modalType: 'INTERACTION',
|
|
modalProps: {
|
|
type,
|
|
accountId: status.getIn(['account', 'id']),
|
|
url: status.get('uri'),
|
|
},
|
|
}));
|
|
},
|
|
|
|
});
|
|
|
|
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status));
|