Add status reference menu

This commit is contained in:
KMY 2023-07-06 17:09:14 +09:00
parent c656f41b35
commit 44a987810b
8 changed files with 84 additions and 3 deletions

View file

@ -62,6 +62,7 @@ export const COMPOSE_LANGUAGE_CHANGE = 'COMPOSE_LANGUAGE_CHANGE';
export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
export const COMPOSE_EXPIRATION_INSERT = 'COMPOSE_EXPIRATION_INSERT';
export const COMPOSE_REFERENCE_INSERT = 'COMPOSE_REFERENCE_INSERT';
export const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST';
export const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS';
@ -770,6 +771,14 @@ export function insertExpirationCompose(position, data) {
};
}
export function insertReferenceCompose(position, url) {
return {
type: COMPOSE_REFERENCE_INSERT,
position,
url,
};
}
export function changeComposing(value) {
return {
type: COMPOSE_COMPOSING_CHANGE,

View file

@ -49,6 +49,7 @@ const messages = defineMessages({
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' },
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to post' },
reference: { id: 'status.reference', defaultMessage: 'Add reference' },
hide: { id: 'status.hide', defaultMessage: 'Hide post' },
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
@ -251,6 +252,10 @@ class StatusActionBar extends ImmutablePureComponent {
navigator.clipboard.writeText(url);
};
handleReference = () => {
this.props.onReference(this.props.status);
};
handleHideClick = () => {
this.props.onFilter();
};
@ -289,6 +294,11 @@ class StatusActionBar extends ImmutablePureComponent {
menu.push(null);
menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancelReblog : messages.reblog), action: this.handleReblogForceModalClick });
if (publicStatus) {
menu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference });
}
menu.push({ text: intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark), action: this.handleBookmarkClick });
if (writtenByMe && pinnableStatus) {

View file

@ -13,6 +13,7 @@ import {
replyCompose,
mentionCompose,
directCompose,
insertReferenceCompose,
} from '../actions/compose';
import {
blockDomain,
@ -192,6 +193,10 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
});
},
onReference (status) {
dispatch(insertReferenceCompose(0, status.get('url')));
},
onTranslate (status) {
if (status.get('translation')) {
dispatch(undoStatusTranslation(status.get('id'), status.get('poll')));

View file

@ -42,6 +42,7 @@ const messages = defineMessages({
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' },
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to post' },
reference: { id: 'status.reference', defaultMessage: 'Add reference' },
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
@ -69,6 +70,7 @@ class ActionBar extends PureComponent {
onReblogForceModal: PropTypes.func.isRequired,
onFavourite: PropTypes.func.isRequired,
onEmojiReact: PropTypes.func.isRequired,
onReference: PropTypes.func.isRequired,
onBookmark: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired,
onEdit: PropTypes.func.isRequired,
@ -190,6 +192,10 @@ class ActionBar extends PureComponent {
navigator.clipboard.writeText(url);
};
handleReference = () => {
this.props.onReference(this.props.status);
};
handleEmojiPick = (data) => {
this.props.onEmojiReact(this.props.status, data);
};
@ -227,6 +233,11 @@ class ActionBar extends PureComponent {
menu.push(null);
menu.push({ text: intl.formatMessage(messages.reblog), action: this.handleReblogForceModalClick });
if (publicStatus) {
menu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference });
}
menu.push(null);
}

View file

@ -28,6 +28,7 @@ import {
replyCompose,
mentionCompose,
directCompose,
insertReferenceCompose,
} from '../../actions/compose';
import {
blockDomain,
@ -356,6 +357,10 @@ class Status extends ImmutablePureComponent {
this.handleReblogClick(status, e, true);
};
handleReference = (status) => {
this.props.dispatch(insertReferenceCompose(0, status.get('url')));
};
handleBookmarkClick = (status) => {
if (status.get('bookmarked')) {
this.props.dispatch(unbookmark(status));
@ -717,6 +722,7 @@ class Status extends ImmutablePureComponent {
onEmojiReact={this.handleEmojiReact}
onReblog={this.handleReblogClick}
onReblogForceModal={this.handleReblogForceModalClick}
onReference={this.handleReference}
onBookmark={this.handleBookmarkClick}
onDelete={this.handleDeleteClick}
onEdit={this.handleEditClick}

View file

@ -419,6 +419,7 @@
"notification.poll": "A poll you have voted in has ended",
"notification.reblog": "{name} boosted your post",
"notification.status": "{name} just posted",
"notification.status_reference": "{name} refered your post",
"notification.update": "{name} edited a post",
"notifications.clear": "Clear notifications",
"notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",

View file

@ -36,6 +36,7 @@ import {
COMPOSE_COMPOSING_CHANGE,
COMPOSE_EMOJI_INSERT,
COMPOSE_EXPIRATION_INSERT,
COMPOSE_REFERENCE_INSERT,
COMPOSE_UPLOAD_CHANGE_REQUEST,
COMPOSE_UPLOAD_CHANGE_SUCCESS,
COMPOSE_UPLOAD_CHANGE_FAIL,
@ -238,6 +239,41 @@ const insertExpiration = (state, position, data) => {
});
};
const insertReference = (state, url) => {
const oldText = state.get('text');
if (oldText.indexOf(`BT ${url}`) >= 0) {
return state;
}
let newLine = '\n\n';
if (oldText.length === 0) newLine = '';
else if (oldText[oldText.length - 1] === '\n') {
if (oldText.length === 1 || oldText[oldText.length - 2] === '\n') {
newLine = '';
} else {
newLine = '\n';
}
}
if (oldText.length > 0) {
const lastLine = oldText.slice(oldText.lastIndexOf('\n') + 1, oldText.length - 1);
if (lastLine.startsWith('BT ')) {
newLine = '\n';
}
}
const referenceText = `${newLine}BT ${url}`;
const text = `${oldText}${referenceText}`;
return state.merge({
text,
focusDate: new Date(),
caretPosition: text.length - referenceText.length,
idempotencyKey: uuid(),
});
};
const privacyPreference = (a, b) => {
const order = ['public', 'public_unlisted', 'unlisted', 'login', 'private', 'direct'];
return order[Math.max(order.indexOf(a), order.indexOf(b), 0)];
@ -476,6 +512,8 @@ export default function compose(state = initialState, action) {
return insertEmoji(state, action.position, action.emoji, action.needsSpace);
case COMPOSE_EXPIRATION_INSERT:
return insertExpiration(state, action.position, action.data);
case COMPOSE_REFERENCE_INSERT:
return insertReference(state, action.url);
case COMPOSE_UPLOAD_CHANGE_SUCCESS:
return state
.set('is_changing_upload', false)

View file

@ -4,7 +4,7 @@ class ProcessReferencesService < BaseService
include Payloadable
DOMAIN = ENV['WEB_DOMAIN'] || ENV.fetch('LOCAL_DOMAIN', nil)
REFURL_EXP = /(RT|QT|BT|RN)((:)? +|:)(#{URI::DEFAULT_PARSER.make_regexp(%w(http https))})/
REFURL_EXP = /(RT|QT|BT|RN|RE)((:)? +|:)(#{URI::DEFAULT_PARSER.make_regexp(%w(http https))})/
STATUSID_EXP = %r{(http|https)://#{DOMAIN}/@[a-zA-Z0-9]+/([0-9]{16,})}
def call(status, reference_parameters, save_records: true, urls: nil)
@ -69,9 +69,10 @@ class ProcessReferencesService < BaseService
end
def create_notifications!
return if @added_objects.empty?
local_reference_objects = @added_objects.filter { |ref| ref.target_status.account.local? }
return if local_reference_objects.empty?
LocalNotificationWorker.push_bulk(@added_objects) do |ref|
LocalNotificationWorker.push_bulk(local_reference_objects) do |ref|
[ref.target_status.account_id, ref.id, 'StatusReference', 'status_reference']
end
end