/** * 消息气泡样式工具 * 参考 Element X 设计,实现动态圆角和现代化气泡样式 */ import { StyleSheet, ViewStyle, TextStyle } from 'react-native'; import { colors, spacing } from '../../../../theme'; // 气泡圆角大小(参考 Element X: 12pt) export const BUBBLE_RADIUS = 16; // 气泡颜色方案(参考 Element X 的语义化颜色) export const bubbleColors = { // 自己发送的消息 outgoing: { background: '#E8E8E8', // Element X 风格:灰色系 text: '#1A1A1A', }, // 收到的消息 incoming: { background: '#FFFFFF', text: '#1A1A1A', }, // 被回复的消息高亮 replyHighlight: { background: 'rgba(255, 107, 53, 0.08)', borderLeft: '#FF6B35', }, }; // 消息在组中的位置类型 export type MessageGroupPosition = 'single' | 'first' | 'middle' | 'last'; /** * 根据消息在组中的位置获取圆角样式 * 参考 Element X 的动态圆角逻辑 */ export const getBubbleBorderRadius = ( isMe: boolean, position: MessageGroupPosition ): ViewStyle => { const radius = BUBBLE_RADIUS; if (isMe) { // 自己发送的消息 switch (position) { case 'single': return { borderTopLeftRadius: radius, borderTopRightRadius: radius, borderBottomLeftRadius: radius, borderBottomRightRadius: 4, // 尖角在右下 }; case 'first': return { borderTopLeftRadius: radius, borderTopRightRadius: radius, borderBottomLeftRadius: radius, borderBottomRightRadius: 4, }; case 'middle': return { borderTopLeftRadius: radius, borderTopRightRadius: 4, borderBottomLeftRadius: radius, borderBottomRightRadius: 4, }; case 'last': return { borderTopLeftRadius: radius, borderTopRightRadius: 4, borderBottomLeftRadius: radius, borderBottomRightRadius: radius, }; } } else { // 收到的消息 switch (position) { case 'single': return { borderTopLeftRadius: 4, // 尖角在左上 borderTopRightRadius: radius, borderBottomLeftRadius: radius, borderBottomRightRadius: radius, }; case 'first': return { borderTopLeftRadius: 4, borderTopRightRadius: radius, borderBottomLeftRadius: 4, borderBottomRightRadius: radius, }; case 'middle': return { borderTopLeftRadius: 4, borderTopRightRadius: radius, borderBottomLeftRadius: 4, borderBottomRightRadius: radius, }; case 'last': return { borderTopLeftRadius: radius, borderTopRightRadius: radius, borderBottomLeftRadius: radius, borderBottomRightRadius: radius, }; } } }; /** * 判断消息在组中的位置 */ export const getMessageGroupPosition = ( index: number, messages: Array<{ sender_id: string }>, currentUserId: string ): MessageGroupPosition => { const currentMessage = messages[index]; if (!currentMessage) return 'single'; const prevMessage = index > 0 ? messages[index - 1] : null; const nextMessage = index < messages.length - 1 ? messages[index + 1] : null; const isSameSenderAsPrev = prevMessage && prevMessage.sender_id === currentMessage.sender_id; const isSameSenderAsNext = nextMessage && nextMessage.sender_id === currentMessage.sender_id; if (!isSameSenderAsPrev && !isSameSenderAsNext) { return 'single'; } else if (!isSameSenderAsPrev && isSameSenderAsNext) { return 'first'; } else if (isSameSenderAsPrev && isSameSenderAsNext) { return 'middle'; } else { return 'last'; } }; /** * 判断是否显示发送者信息(只在组的第一条消息显示) */ export const shouldShowSenderInfo = ( index: number, messages: Array<{ sender_id: string }>, ): boolean => { if (index === 0) return true; const currentMessage = messages[index]; const prevMessage = messages[index - 1]; return prevMessage.sender_id !== currentMessage.sender_id; }; /** * 获取气泡基础样式 */ export const getBubbleBaseStyle = (isMe: boolean): ViewStyle => ({ paddingHorizontal: spacing.md, paddingVertical: spacing.sm + 4, minWidth: 60, maxWidth: '75%', backgroundColor: isMe ? bubbleColors.outgoing.background : bubbleColors.incoming.background, // Element X 风格的微妙阴影 shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.06, shadowRadius: 2, elevation: 2, }); /** * 获取文本样式 */ export const getBubbleTextStyle = (isMe: boolean): TextStyle => ({ color: isMe ? bubbleColors.outgoing.text : bubbleColors.incoming.text, fontSize: 16, lineHeight: 23, letterSpacing: 0.2, fontWeight: '400', }); /** * 消息气泡样式集合 */ export const bubbleStyles = StyleSheet.create({ // 基础气泡 bubble: { paddingHorizontal: spacing.md, paddingVertical: spacing.sm + 4, minWidth: 60, }, // 自己发送的消息 outgoing: { backgroundColor: bubbleColors.outgoing.background, }, // 收到的消息 incoming: { backgroundColor: bubbleColors.incoming.background, }, // 文本样式 text: { fontSize: 16, lineHeight: 23, letterSpacing: 0.2, fontWeight: '400', }, // 阴影样式(Element X 风格) shadow: { shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.06, shadowRadius: 2, elevation: 2, }, // 长按反馈阴影 longPressShadow: { shadowColor: '#000', shadowOffset: { width: 0, height: 3 }, shadowOpacity: 0.12, shadowRadius: 8, elevation: 6, }, // 被回复消息的高亮边框 replyHighlight: { borderLeftWidth: 3, borderLeftColor: colors.primary.main, backgroundColor: bubbleColors.replyHighlight.background, }, // 已撤回消息 recalled: { backgroundColor: '#F5F7FA', borderWidth: 1, borderColor: '#E8E8E8', borderStyle: 'dashed', borderRadius: 12, }, // 系统通知 systemNotice: { alignItems: 'center', marginVertical: spacing.sm, }, systemNoticeText: { fontSize: 12, color: '#8E8E93', backgroundColor: 'rgba(142, 142, 147, 0.12)', paddingHorizontal: spacing.md, paddingVertical: spacing.xs, borderRadius: 12, overflow: 'hidden', }, }); export default { BUBBLE_RADIUS, bubbleColors, getBubbleBorderRadius, getMessageGroupPosition, shouldShowSenderInfo, getBubbleBaseStyle, getBubbleTextStyle, bubbleStyles, };