feat: 实现跨端引用回复协议,新增 QuoteBar 组件支持消息引用
本次提交实现了与 iOS 对齐的跨端消息引用协议,新增 QuoteBar 组件用于渲染引用消息栏,重构发送逻辑支持文本和媒体消息的引用功能。主要改动包括: - 新增 reply.ts 处理引用数据的构建和解析 - 新增 QuoteBar 组件渲染引用消息预览 - 重构发送逻辑,将引用快照放入消息头部而非内容 - 调整代理配置指向本地开发环境 - 优化消息操作权限,支持名片和媒体消息引用
This commit is contained in:
@@ -16,6 +16,8 @@ import {
|
||||
} from '@/lib/messages/dispatch';
|
||||
import { renderDrafty } from '@/lib/messages/drafty';
|
||||
import { AudioAttachment, FileAttachment, ImageAttachment, VideoAttachment } from '@/features/messages/AttachmentPreview';
|
||||
import { QuoteBar } from '@/features/messages/QuoteBar';
|
||||
import { parseReplyHead } from '@/lib/messages/reply';
|
||||
import { formatBubbleTime, formatEventTimestamp } from '@/lib/messages/time';
|
||||
import { isFailedStatus, isSendingStatus, outgoingStatusLabel } from '@/lib/messages/status';
|
||||
import { groupSenderLabel } from '@/lib/messages/sender-name';
|
||||
@@ -74,6 +76,10 @@ interface MessageRowProps {
|
||||
highlighted?: boolean;
|
||||
onToggleSelect?: (seq: number) => void;
|
||||
onContextMenu?: (e: React.MouseEvent, msg: StoredMessage) => void;
|
||||
/** Resolves a QUOTED message's sender uid (from head["x-im-reply"].from) to a display label.
|
||||
* Owned by ConversationView so group remark/nickname resolution stays in one place; QuoteBar
|
||||
* must never print a raw uid. */
|
||||
resolveQuotedName?: (uid: string | undefined) => string;
|
||||
/** Fired when the inline "重试" retry (below) itself fails -- e.g. still offline. Without this the
|
||||
* failed-send icon just silently stays put with no feedback at all that the retry attempt was
|
||||
* even made. */
|
||||
@@ -95,6 +101,7 @@ export function MessageRow({
|
||||
highlighted,
|
||||
onToggleSelect,
|
||||
onContextMenu,
|
||||
resolveQuotedName,
|
||||
onError,
|
||||
}: MessageRowProps) {
|
||||
if (isServerDeleted(msg)) {
|
||||
@@ -121,6 +128,9 @@ export function MessageRow({
|
||||
const callResult = callResultDisplay(msg, mine);
|
||||
const contactCard = contactCardContentOf(msg);
|
||||
const mobileAttachment = mobileAttachmentContentOf(msg);
|
||||
// Quoted-reply snapshot (x-im-reply). Not rendered for a recalled message -- its whole bubble
|
||||
// collapses to the "消息已删除" placeholder, quote bar included.
|
||||
const replyInfo = isRecalled(msg) ? null : parseReplyHead(msg.head);
|
||||
|
||||
const retry = () => {
|
||||
if (typeof msg.seq !== 'number') return;
|
||||
@@ -201,6 +211,9 @@ export function MessageRow({
|
||||
mine ? 'rounded-[12px_4px_12px_12px] bg-bubble-mine' : 'rounded-[4px_12px_12px_12px] bg-white shadow-bubble'
|
||||
} ${isRecalled(msg) ? 'text-text-tertiary-4 italic' : ''} ${menuActive ? 'outline outline-2 outline-offset-2 outline-accent' : ''}`}
|
||||
>
|
||||
{replyInfo ? (
|
||||
<QuoteBar topicName={topic.name} reply={replyInfo} resolveName={resolveQuotedName ?? (() => '消息')} />
|
||||
) : null}
|
||||
{isRecalled(msg) ? (
|
||||
'⚠ 消息已删除'
|
||||
) : callResult ? (
|
||||
|
||||
Reference in New Issue
Block a user