mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
feat(app): make +emoji react on send and target replies (#2998)
This commit is contained in:
@@ -57,6 +57,7 @@ import type {GuildMember} from '@app/features/member/models/GuildMember';
|
||||
import GuildMembers from '@app/features/member/state/GuildMembers';
|
||||
import type {SearchContext} from '@app/features/member/state/MemberSearch';
|
||||
import * as HighlightCommands from '@app/features/messaging/commands/HighlightCommands';
|
||||
import * as MessageCommands from '@app/features/messaging/commands/MessageCommands';
|
||||
import * as ReactionCommands from '@app/features/messaging/commands/ReactionCommands';
|
||||
import Messages from '@app/features/messaging/state/MessagingMessages';
|
||||
import {
|
||||
@@ -77,6 +78,7 @@ import {
|
||||
} from '@app/features/messaging/utils/AutocompleteOptionBuilders';
|
||||
import {isAutocompleteTriggerAllowed, type TriggerType} from '@app/features/messaging/utils/AutocompleteTriggerPolicy';
|
||||
import {toReactionEmoji} from '@app/features/messaging/utils/MessageReactionUtils';
|
||||
import {getReactionShorthandTargetId} from '@app/features/messaging/utils/ReactionShorthandUtils';
|
||||
import {
|
||||
type AutocompleteTrigger,
|
||||
detectAutocompleteTrigger,
|
||||
@@ -705,10 +707,10 @@ export function useLexicalAutocomplete({
|
||||
const matchStart = getComposerAutocompleteReplacementStart(currentTextUpToCursor, trigger.type, trigger.match);
|
||||
if (trigger.type === 'emojiReaction' && isEmoji(option)) {
|
||||
if (channel != null) {
|
||||
const messages = Messages.getMessages(channel.id).toArray();
|
||||
const mostRecent = messages[messages.length - 1];
|
||||
if (mostRecent != null) {
|
||||
ReactionCommands.addReaction(i18n, channel.id, mostRecent.id, toReactionEmoji(option.emoji));
|
||||
const targetId = getReactionShorthandTargetId(channel.id);
|
||||
if (targetId !== null) {
|
||||
ReactionCommands.addReaction(i18n, channel.id, targetId, toReactionEmoji(option.emoji));
|
||||
MessageCommands.stopReply(channel.id);
|
||||
}
|
||||
}
|
||||
handle.clear();
|
||||
|
||||
@@ -20,6 +20,7 @@ import GuildMembers from '@app/features/member/state/GuildMembers';
|
||||
import MemberSidebar from '@app/features/member/state/MemberSidebar';
|
||||
import * as DraftCommands from '@app/features/messaging/commands/DraftCommands';
|
||||
import * as MessageCommands from '@app/features/messaging/commands/MessageCommands';
|
||||
import * as ReactionCommands from '@app/features/messaging/commands/ReactionCommands';
|
||||
import type {Message} from '@app/features/messaging/models/MessagingMessage';
|
||||
import type {MentionConfirmationInfo, MentionType} from '@app/features/messaging/state/MentionConfirmationStateMachine';
|
||||
import Messages from '@app/features/messaging/state/MessagingMessages';
|
||||
@@ -29,6 +30,10 @@ import {
|
||||
isAttachmentOnlyMessage,
|
||||
} from '@app/features/messaging/utils/MessageEditContentUtils';
|
||||
import {canSubmitMessage, hasVisibleMessageContent} from '@app/features/messaging/utils/MessageRequestUtils';
|
||||
import {
|
||||
getReactionShorthandTargetId,
|
||||
parseReactionShorthand,
|
||||
} from '@app/features/messaging/utils/ReactionShorthandUtils';
|
||||
import * as ReplaceCommandUtils from '@app/features/messaging/utils/ReplaceCommandUtils';
|
||||
import {resolveTypedEmojiShortcodes} from '@app/features/messaging/utils/TypedEmojiShortcodeUtils';
|
||||
import Permission from '@app/features/permissions/state/Permission';
|
||||
@@ -458,6 +463,20 @@ export const useTextareaSubmit = ({
|
||||
parsedCommand = lexicalCommand.command;
|
||||
}
|
||||
const replaceCommand = ReplaceCommandUtils.parseReplaceCommand(actualContent);
|
||||
const reactionShorthand =
|
||||
editingMessage === null && uploadAttachmentsLength === 0 && !hasPendingSticker
|
||||
? parseReactionShorthand(resolvedContent)
|
||||
: null;
|
||||
const reactionTargetId = reactionShorthand === null ? null : getReactionShorthandTargetId(channelId);
|
||||
if (reactionShorthand !== null && reactionTargetId !== null) {
|
||||
ReactionCommands.addReaction(i18n, channelId, reactionTargetId, reactionShorthand);
|
||||
setValue('');
|
||||
clearSegments();
|
||||
DraftCommands.deleteDraft(channelId);
|
||||
TypingUtils.clear(channelId);
|
||||
MessageCommands.stopReply(channelId);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
shouldBlockSubmissionForSlowmode(
|
||||
isSlowmodeActive,
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import UnicodeEmojis from '@app/features/expressions/utils/UnicodeEmojis';
|
||||
import MessageReply from '@app/features/messaging/state/MessageReply';
|
||||
import Messages from '@app/features/messaging/state/MessagingMessages';
|
||||
import {type ReactionEmoji, toReactionEmoji} from '@app/features/messaging/utils/MessageReactionUtils';
|
||||
|
||||
const REACTION_SHORTHAND_PATTERN = /^\+(\S+)$/u;
|
||||
const CUSTOM_EMOJI_MARKDOWN_PATTERN = /^<(a)?:([a-zA-Z0-9_+-]{2,}):(\d+)>$/;
|
||||
const SHORTCODE_PATTERN = /^:([^\s:]+):$/;
|
||||
|
||||
export function parseReactionShorthand(content: string): ReactionEmoji | null {
|
||||
const match = REACTION_SHORTHAND_PATTERN.exec(content.trim());
|
||||
if (match === null) {
|
||||
return null;
|
||||
}
|
||||
const token = match[1];
|
||||
const customMatch = CUSTOM_EMOJI_MARKDOWN_PATTERN.exec(token);
|
||||
if (customMatch !== null) {
|
||||
return {id: customMatch[3], name: customMatch[2], animated: customMatch[1] === 'a'};
|
||||
}
|
||||
const shortcodeMatch = SHORTCODE_PATTERN.exec(token);
|
||||
if (shortcodeMatch !== null) {
|
||||
const emoji = UnicodeEmojis.findEmojiByShortcodeName(shortcodeMatch[1]);
|
||||
return emoji === null ? null : toReactionEmoji(emoji);
|
||||
}
|
||||
const name = UnicodeEmojis.nameForSurrogate(token, false);
|
||||
if (name === '') {
|
||||
return null;
|
||||
}
|
||||
return {name: UnicodeEmojis.surrogateForName(name, token)};
|
||||
}
|
||||
|
||||
export function getReactionShorthandTargetId(channelId: string): string | null {
|
||||
const reply = MessageReply.getReplyingMessage(channelId);
|
||||
if (reply !== null) {
|
||||
return reply.messageId;
|
||||
}
|
||||
const messages = Messages.getMessages(channelId).toArray();
|
||||
return messages[messages.length - 1]?.id ?? null;
|
||||
}
|
||||
Reference in New Issue
Block a user