Files
frontend/src/screens/message/components/ChatScreen/styles.ts
lafay be77a9d04c
All checks were successful
Frontend CI / ota (android) (push) Successful in 3m24s
Frontend CI / ota (ios) (push) Successful in 3m22s
Frontend CI / build-and-push-web (push) Successful in 21m12s
Frontend CI / build-android-apk (push) Successful in 41m40s
feat(messaging): implement optimistic updates with retry for failed messages
- Add pending/failed message status to track send state
- Implement optimistic UI: show message immediately, update on server response
- Add retry functionality for failed messages via tap-to-retry
- Change send button from icon to text "发送" for clarity
- Add MessageSendService with temp ID generation to prevent collisions

feat(notification): add JPush notification deduplication and clear on tap

- Deduplicate notificationArrived events from dual JPush/vendor channels
- Clear all notifications on tap (QQ-style behavior)

feat(post): add client-side idempotency key for post creation

- Generate client_request_id per publish intent to prevent duplicates on retry
- Pass idempotency key through to postService and voteService
2026-06-26 17:01:09 +08:00

1344 lines
32 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* ChatScreen 样式定义
* 支持响应式布局和动态聊天设置
*/
import { useMemo } from 'react';
import { StyleSheet, Dimensions } from 'react-native';
import { spacing, shadows, useAppColors, type AppColors } from '../../../../theme';
import { useChatSettingsStore, CHAT_THEMES } from '../../../../stores/settings';
const { width: SCREEN_WIDTH } = Dimensions.get('window');
// 响应式断点
const BREAKPOINTS = {
tablet: 768,
desktop: 1024,
};
// 判断是否为宽屏
const isWideScreen = SCREEN_WIDTH >= BREAKPOINTS.desktop;
const isTablet = SCREEN_WIDTH >= BREAKPOINTS.tablet;
// Hook 获取动态样式参数
export function useChatDynamicStyles() {
const fontSize = useChatSettingsStore((s) => s.fontSize);
const messageRadius = useChatSettingsStore((s) => s.messageRadius);
const themeIndex = useChatSettingsStore((s) => s.themeIndex);
const nightMode = useChatSettingsStore((s) => s.nightMode);
const theme = CHAT_THEMES[themeIndex];
const colors = useAppColors();
// 夜间模式优先:当开启夜间模式时,使用系统暗色,忽略主题设置
// 判断是否为暗色模式chat.nightMode 设置 或 系统暗色模式(背景色为暗色)
const isSystemDarkMode = (colors.chat.screen as string).startsWith('#0') ||
(colors.chat.screen as string) === '#0A0A0A' ||
(colors.chat.screen as string) === '#121212';
const isNightMode = nightMode || isSystemDarkMode;
return {
fontSize,
messageRadius,
// 夜间模式时使用系统暗色,否则使用主题色
outgoingBubbleColor: isNightMode ? colors.chat.bubbleOutgoing : theme.bubble,
// 对方消息气泡背景色 - 使用纯白以区分header和背景
theirBubbleBackgroundColor: isNightMode ? colors.chat.card : '#FFFFFF',
// 背景色
chatBackgroundColor: isNightMode ? colors.chat.screen : theme.secondary,
// 卡片/头部背景色 - 使用主题次级色(稍深)
cardBackgroundColor: isNightMode ? colors.chat.card : theme.secondary,
// 输入框背景色 - 使用纯白以保持对比度
inputBackgroundColor: isNightMode ? colors.chat.surfaceRaised : '#FFFFFF',
// 面板背景色
panelBackgroundColor: isNightMode ? colors.chat.surfaceMuted : theme.panelBg,
// 主要文字颜色
textPrimaryColor: isNightMode ? colors.chat.textPrimary : theme.textPrimary,
// 次要文字颜色
textSecondaryColor: isNightMode ? colors.chat.textSecondary : theme.textSecondary,
};
};
export function createChatScreenStyles(colors: AppColors, dynamicStyles?: {
fontSize?: number;
messageRadius?: number;
outgoingBubbleColor?: string;
theirBubbleBackgroundColor?: string;
chatBackgroundColor?: string;
cardBackgroundColor?: string;
inputBackgroundColor?: string;
panelBackgroundColor?: string;
textPrimaryColor?: string;
textSecondaryColor?: string;
}) {
const fontSize = dynamicStyles?.fontSize ?? 16;
const messageRadius = dynamicStyles?.messageRadius ?? 12;
// 主题颜色(优先使用主题色,否则使用默认色)
const myBubbleBg = dynamicStyles?.outgoingBubbleColor || colors.chat.bubbleOutgoing;
const theirBubbleBg = dynamicStyles?.theirBubbleBackgroundColor || colors.chat.card;
const screenBgColor = dynamicStyles?.chatBackgroundColor || colors.chat.screen;
const cardBgColor = dynamicStyles?.cardBackgroundColor || colors.chat.card;
const inputBgColor = dynamicStyles?.inputBackgroundColor || colors.chat.surfaceRaised;
const panelBgColor = dynamicStyles?.panelBackgroundColor || colors.chat.surfaceMuted;
const textPrimary = dynamicStyles?.textPrimaryColor || colors.chat.textPrimary;
const textSecondary = dynamicStyles?.textSecondaryColor || colors.chat.textSecondary;
return StyleSheet.create({
// 容器
container: {
flex: 1,
backgroundColor: screenBgColor,
},
// 头部
headerContainer: {
backgroundColor: cardBgColor,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: colors.chat.border,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm + 2,
backgroundColor: cardBgColor,
height: 56,
},
headerLeft: {
flexDirection: 'row',
alignItems: 'center',
gap: spacing.xs,
zIndex: 2,
},
backButton: {
width: 40,
height: 40,
alignItems: 'center',
justifyContent: 'center',
marginLeft: -12,
padding: 0,
},
headerCenter: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 50,
},
titleRow: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: spacing.xs,
borderRadius: 8,
},
groupAvatar: {
width: 36,
height: 36,
borderRadius: 10,
},
titleContent: {
flex: 1,
minWidth: 0,
alignItems: 'center',
},
subtitleRow: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 2,
gap: spacing.xs,
minHeight: 16,
},
headerName: {
fontWeight: '600',
color: textPrimary,
fontSize: 16,
letterSpacing: -0.3,
},
memberCount: {
fontSize: 12,
color: textSecondary,
fontWeight: '400',
},
typingHint: {
fontSize: 12,
color: colors.primary.main,
fontWeight: '500',
},
moreButton: {
width: 36,
height: 36,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 10,
backgroundColor: 'transparent',
},
headerActions: {
flexDirection: 'row',
alignItems: 'center',
gap: spacing.xs,
},
callButton: {
width: 38,
height: 38,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 19,
backgroundColor: `${colors.primary.main}12`,
},
// 消息列表
messageListContainer: {
flex: 1,
},
// 回到底部Telegram 式浮动条)
jumpToLatestFab: {
position: 'absolute',
right: 14,
bottom: 10,
flexDirection: 'row',
alignItems: 'center',
gap: 6,
paddingHorizontal: 12,
paddingVertical: 8,
borderRadius: 20,
backgroundColor: 'rgba(255, 255, 255, 0.96)',
borderWidth: StyleSheet.hairlineWidth,
borderColor: 'rgba(0, 0, 0, 0.08)',
},
jumpToLatestFabText: {
fontSize: 13,
fontWeight: '600',
color: colors.primary.main,
},
listContent: {
paddingHorizontal: spacing.md,
paddingTop: spacing.md,
paddingBottom: spacing.xl,
},
// 时间分隔 - 轻量胶囊(弱化字重,接近 Telegram 日期条)
timeContainer: {
alignItems: 'center',
marginVertical: spacing.lg,
},
timeText: {
color: 'rgba(142, 142, 147, 0.95)',
fontSize: 11,
backgroundColor: 'rgba(142, 142, 147, 0.1)',
paddingHorizontal: spacing.sm + 4,
paddingVertical: 5,
borderRadius: 12,
fontWeight: '500',
overflow: 'hidden',
letterSpacing: 0.2,
},
// 系统通知
systemNoticeContainer: {
alignItems: 'center',
marginVertical: spacing.sm,
paddingHorizontal: spacing.md,
},
systemNoticeText: {
fontSize: 12,
color: colors.chat.textSecondary,
backgroundColor: 'rgba(142, 142, 147, 0.12)',
paddingHorizontal: spacing.md,
paddingVertical: spacing.xs,
borderRadius: 12,
overflow: 'hidden',
},
// 消息行
messageRow: {
flexDirection: 'row',
marginBottom: spacing.md,
alignItems: 'flex-start',
},
myMessageRow: {
justifyContent: 'flex-end',
},
theirMessageRow: {
justifyContent: 'flex-start',
},
// 头像 - 更大一点
avatarWrapper: {
marginHorizontal: 2,
shadowColor: colors.chat.shadow,
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.08,
shadowRadius: 2,
elevation: 2,
},
groupAvatarWrapper: {
marginHorizontal: 2,
shadowColor: colors.chat.shadow,
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.08,
shadowRadius: 2,
elevation: 2,
},
// 消息内容 - 自适应宽度,限制最大宽度
messageContent: {
maxWidth: '75%',
marginHorizontal: spacing.xs,
alignItems: 'flex-start',
},
senderName: {
fontSize: 12,
color: textSecondary,
marginBottom: 4,
marginLeft: 4,
fontWeight: '500',
},
mySenderName: {
marginLeft: 0,
marginRight: 4,
alignSelf: 'flex-end',
},
// 消息气泡 - 动态圆角支持
messageBubbleOuter: {
borderRadius: messageRadius,
minWidth: 44,
},
myBubbleOuter: {
borderTopRightRadius: Math.max(4, messageRadius * 0.3), // 箭头在右上
},
theirBubbleOuter: {
borderTopLeftRadius: Math.max(4, messageRadius * 0.3),
},
// 内层:动态圆角支持
messageBubbleInner: {
borderRadius: messageRadius,
overflow: 'hidden',
paddingHorizontal: 10, // 微信:更窄的左右边距
paddingVertical: 7, // 微信:更紧的上下边距
minWidth: 44,
},
myBubbleInner: {
backgroundColor: myBubbleBg,
borderTopRightRadius: Math.max(4, messageRadius * 0.3),
},
theirBubbleInner: {
backgroundColor: theirBubbleBg,
borderTopLeftRadius: Math.max(4, messageRadius * 0.3),
},
recalledBubble: {
backgroundColor: panelBgColor,
borderWidth: 1,
borderColor: colors.chat.border,
borderStyle: 'dashed',
},
myBubbleText: {
color: textPrimary, // 使用主题文字颜色
fontSize,
lineHeight: Math.round(fontSize * 1.4),
letterSpacing: 0.1,
fontWeight: '400',
},
theirBubbleText: {
color: textPrimary, // 使用主题文字颜色
fontSize,
lineHeight: Math.round(fontSize * 1.4),
letterSpacing: 0.1,
fontWeight: '400',
},
// 选中状态
selectedBubble: {
borderWidth: 2,
borderColor: colors.chat.replyBorder,
},
// 仅对齐右侧,不再套一层浅色底,避免与气泡叠色产生「边缘多出一块蓝」
myMessageContentPanel: {
alignItems: 'flex-end',
},
mySelectedBubble: {
backgroundColor: colors.chat.replyTintActive,
borderWidth: 2,
borderColor: colors.chat.replyBorder,
},
theirSelectedBubble: {
backgroundColor: colors.chat.menuHighlight,
borderWidth: 2,
borderColor: colors.chat.replyBorder,
},
selectedText: {
// 文本选中时的样式
},
recalledText: {
color: colors.chat.textSecondary,
fontStyle: 'italic',
},
// 图片消息 - QQ/微信风格:更大的圆角,更柔和的阴影
imageBubble: {
borderRadius: 18,
overflow: 'hidden',
shadowColor: colors.chat.shadow,
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.12,
shadowRadius: 6,
elevation: 4,
},
myImageBubble: {
borderTopRightRadius: 8,
},
theirImageBubble: {
borderTopLeftRadius: 8,
},
messageImage: {
width: 220,
height: 220,
borderRadius: 18,
},
// 已读状态
readStatusContainer: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'flex-end',
marginTop: 2,
marginRight: 2,
gap: 2,
},
readStatusText: {
fontSize: 10,
color: colors.chat.textSecondary,
fontWeight: '500',
},
readStatusTextRead: {
color: colors.chat.success,
},
// 发送状态(乐观更新)
sendStatusContainer: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'flex-end',
marginTop: 2,
marginRight: 2,
},
sendStatusRow: {
flexDirection: 'row',
alignItems: 'center',
gap: 2,
},
sendStatusIndicator: {
marginRight: 2,
},
pendingStatusText: {
fontSize: 10,
color: colors.chat.textSecondary,
fontWeight: '500',
},
failedStatusText: {
fontSize: 10,
color: '#FF3B30',
fontWeight: '500',
},
// 输入框区域 - 与列表背景同色底栏,顶部细分隔
inputWrapper: {
backgroundColor: cardBgColor,
borderTopWidth: StyleSheet.hairlineWidth,
borderTopColor: colors.chat.borderHairline,
},
inputContainer: {
backgroundColor: 'transparent',
borderWidth: 0,
borderRadius: 0,
marginHorizontal: 10,
marginBottom: 6,
marginTop: 6,
paddingHorizontal: spacing.sm,
paddingVertical: spacing.sm,
shadowColor: 'transparent',
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0,
shadowRadius: 0,
elevation: 0,
},
inputInner: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.chat.surfaceRaised,
borderRadius: 20,
paddingHorizontal: spacing.xs,
paddingVertical: 4,
minHeight: 44,
// 移除阴影效果
shadowColor: 'transparent',
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0,
shadowRadius: 0,
elevation: 0,
},
inputInnerMuted: {
backgroundColor: colors.chat.surfaceMuted,
opacity: 0.7,
},
// 禁言提示
mutedBanner: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: colors.chat.warningBg,
paddingVertical: spacing.xs,
paddingHorizontal: spacing.md,
marginBottom: spacing.xs,
borderRadius: 8,
gap: 6,
},
mutedBannerText: {
fontSize: 13,
color: colors.chat.danger,
fontWeight: '500',
},
// 图标按钮
iconButton: {
width: 38,
height: 30,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 15,
},
iconButtonActive: {
backgroundColor: `${colors.primary.main}20`,
transform: [{ translateY: -1 }],
},
// 发送按钮 - 微信风格文字按钮
sendButtonActive: {
minWidth: 56,
height: 34,
borderRadius: 8,
backgroundColor: colors.primary.main,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 12,
// 轻微阴影
shadowColor: colors.primary.main,
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.2,
shadowRadius: 2,
elevation: 2,
},
sendButtonDisabled: {
opacity: 0.4,
},
sendButtonText: {
color: '#FFF',
fontSize: 14,
fontWeight: '600',
letterSpacing: 0.5,
},
// 输入框
inputBox: {
flex: 1,
paddingHorizontal: spacing.xs,
maxHeight: 100,
justifyContent: 'center',
// 移除阴影
shadowColor: 'transparent',
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0,
shadowRadius: 0,
elevation: 0,
},
input: {
fontSize: 16,
color: colors.chat.textPrimary,
paddingTop: 8,
paddingBottom: 8,
maxHeight: 100,
lineHeight: 20,
},
inputMuted: {
color: colors.chat.iconMuted,
},
// 输入框@高亮
inputHighlightOverlay: {
...StyleSheet.absoluteFill,
flexDirection: 'row',
flexWrap: 'wrap',
paddingTop: 8,
paddingBottom: 8,
},
inputHighlightText: {
fontSize: 16,
color: colors.chat.textPrimary,
lineHeight: 20,
},
inputHighlightMention: {
color: colors.primary.main,
fontWeight: '600',
},
// 加载状态
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingVertical: spacing.xl * 2,
},
// 面板
panelWrapper: {
backgroundColor: cardBgColor,
borderTopWidth: StyleSheet.hairlineWidth,
borderTopColor: colors.chat.borderHairline,
},
// 表情面板包装器 - 底部 tab 栏是白色,安全区域也用白色填充
emojiPanelWrapper: {
backgroundColor: cardBgColor,
},
panelContainer: {
flex: 1,
backgroundColor: cardBgColor,
},
morePanelBackground: {
flex: 1,
backgroundColor: cardBgColor,
},
// 表情面板
emojiGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
paddingHorizontal: spacing.md,
paddingTop: spacing.md,
paddingBottom: spacing.xl,
alignItems: 'flex-start',
backgroundColor: cardBgColor,
},
emojiItem: {
width: '12.5%',
height: 52,
alignItems: 'center',
justifyContent: 'center',
},
emojiText: {
fontSize: 28,
lineHeight: 34,
},
panelFooter: {
flexDirection: 'row',
justifyContent: 'flex-end',
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
borderTopWidth: 1,
borderTopColor: colors.chat.border,
},
// 面板内容区域
panelContent: {
flex: 1,
},
// Tab 栏 - 底部横向导航条QQ/微信风格)
panelTabBar: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 0,
paddingVertical: 0,
backgroundColor: cardBgColor,
borderTopWidth: StyleSheet.hairlineWidth,
borderTopColor: colors.chat.borderHairline,
},
panelTabScroll: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: spacing.sm,
gap: spacing.sm,
},
panelTabItem: {
alignItems: 'center',
justifyContent: 'center',
width: 48,
height: 44,
borderBottomWidth: 2.5,
borderBottomColor: 'transparent',
},
panelTabItemActive: {
borderBottomColor: colors.primary.main,
},
panelCloseButton: {
width: 44,
height: 44,
alignItems: 'center',
justifyContent: 'center',
marginRight: spacing.sm,
},
// 自定义表情面板
stickerLoadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: cardBgColor,
},
stickerEmptyContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: spacing.xl,
backgroundColor: cardBgColor,
},
stickerEmptyText: {
fontSize: 16,
color: colors.chat.textTertiary,
marginTop: spacing.md,
fontWeight: '500',
},
stickerEmptySubText: {
fontSize: 13,
color: colors.chat.textMuted,
marginTop: spacing.xs,
},
stickerGrid: {
flex: 1,
paddingHorizontal: spacing.md,
paddingTop: spacing.md,
paddingBottom: spacing.xl,
backgroundColor: cardBgColor,
},
stickerItem: {
width: (SCREEN_WIDTH - spacing.md * 2) / 4 - 8,
height: (SCREEN_WIDTH - spacing.md * 2) / 4 - 8,
margin: 4,
borderRadius: 8,
overflow: 'hidden',
backgroundColor: inputBgColor,
},
stickerImage: {
width: '100%',
height: '100%',
},
// 更多功能面板 - 现代扁平化设计
moreGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
paddingHorizontal: spacing.lg + 4,
paddingTop: spacing.md,
paddingBottom: spacing.xl,
justifyContent: 'flex-start',
backgroundColor: cardBgColor,
},
moreItem: {
width: (SCREEN_WIDTH - spacing.lg * 2 - 8) / 4,
alignItems: 'center',
marginBottom: spacing.lg + 4,
},
moreIconContainer: {
width: 56,
height: 56,
borderRadius: 18,
alignItems: 'center',
justifyContent: 'center',
marginBottom: spacing.sm + 2,
backgroundColor: cardBgColor,
shadowColor: colors.chat.shadow,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.06,
shadowRadius: 6,
elevation: 2,
},
moreIconGradient: {
width: 56,
height: 56,
borderRadius: 18,
alignItems: 'center',
justifyContent: 'center',
marginBottom: spacing.sm + 2,
overflow: 'hidden',
},
moreIconInner: {
width: 56,
height: 56,
borderRadius: 18,
alignItems: 'center',
justifyContent: 'center',
},
moreItemText: {
fontSize: 12,
color: textSecondary,
fontWeight: '500',
letterSpacing: 0.3,
},
// @成员选择浮层 - 绝对定位浮在输入框上方
mentionPanelFloat: {
position: 'absolute',
left: 12,
right: 12,
backgroundColor: cardBgColor,
borderRadius: 18,
shadowColor: colors.primary.main,
shadowOffset: { width: 0, height: -3 },
shadowOpacity: 0.12,
shadowRadius: 16,
elevation: 24,
zIndex: 100,
borderWidth: 1,
borderColor: 'rgba(255, 107, 53, 0.08)',
},
// @成员选择面板
mentionPanelContainer: {
flex: 1,
backgroundColor: cardBgColor,
borderRadius: 18,
},
mentionPanelDragHandle: {
alignItems: 'center',
paddingTop: 8,
paddingBottom: 2,
},
mentionPanelDragBar: {
width: 32,
height: 3,
borderRadius: 2,
backgroundColor: colors.chat.sheetGrip,
},
mentionPanelHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingHorizontal: spacing.md,
paddingTop: 4,
paddingBottom: 8,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: colors.chat.borderHairline,
},
mentionPanelTitle: {
fontSize: 12,
fontWeight: '600',
color: colors.chat.textPlaceholder,
letterSpacing: 0.5,
textTransform: 'uppercase',
},
mentionPanelCloseBtn: {
width: 26,
height: 26,
borderRadius: 13,
backgroundColor: inputBgColor,
alignItems: 'center',
justifyContent: 'center',
},
mentionList: {
flex: 1,
},
mentionItem: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: spacing.md,
paddingVertical: 9,
},
mentionItemAll: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: spacing.md,
paddingVertical: 9,
backgroundColor: 'rgba(255, 107, 53, 0.04)',
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: 'rgba(255, 107, 53, 0.12)',
},
mentionAllIcon: {
width: 38,
height: 38,
borderRadius: 19,
backgroundColor: colors.primary.main,
alignItems: 'center',
justifyContent: 'center',
shadowColor: colors.primary.main,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.3,
shadowRadius: 4,
elevation: 3,
},
mentionItemInfo: {
marginLeft: 10,
flex: 1,
},
mentionItemName: {
fontSize: 15,
fontWeight: '500',
color: colors.chat.textPrimary,
},
mentionItemNameAll: {
fontSize: 15,
fontWeight: '600',
color: colors.primary.main,
},
mentionItemSub: {
fontSize: 12,
color: colors.chat.iconMuted,
marginTop: 1,
},
mentionItemRole: {
fontSize: 11,
color: colors.primary.main,
marginTop: 2,
fontWeight: '500',
},
mentionEmpty: {
paddingVertical: spacing.xl,
alignItems: 'center',
},
mentionEmptyText: {
fontSize: 14,
color: colors.chat.iconSoft,
},
// 长按菜单 - 底部横条形式类似QQ
menuOverlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.4)',
justifyContent: 'flex-end',
},
// 旧版菜单样式(保留兼容)
menuContainer: {
backgroundColor: cardBgColor,
borderRadius: 12,
minWidth: 160,
shadowColor: colors.chat.shadow,
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.15,
shadowRadius: 12,
elevation: 8,
},
menuItem: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 16,
paddingVertical: 12,
gap: 12,
},
menuItemBorder: {
borderBottomWidth: 1,
borderBottomColor: colors.chat.borderHairline,
},
menuItemText: {
fontSize: 15,
color: textPrimary,
fontWeight: '500',
},
// 底部菜单容器
bottomMenuContainer: {
backgroundColor: cardBgColor,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
paddingTop: spacing.md,
paddingBottom: spacing.xl,
shadowColor: colors.chat.shadow,
shadowOffset: { width: 0, height: -4 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 16,
},
// 消息预览区域
messagePreviewContainer: {
backgroundColor: panelBgColor,
marginHorizontal: spacing.md,
marginBottom: spacing.md,
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
borderRadius: 12,
maxHeight: 80,
},
messagePreviewText: {
fontSize: 14,
color: colors.chat.textTertiary,
lineHeight: 20,
},
// 操作按钮横条
menuActionsRow: {
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'flex-start',
paddingHorizontal: spacing.sm,
paddingVertical: spacing.md,
borderBottomWidth: 1,
borderBottomColor: colors.chat.borderHairline,
marginBottom: spacing.md,
},
menuActionItem: {
alignItems: 'center',
justifyContent: 'center',
minWidth: 64,
},
menuActionItemLast: {
marginRight: 0,
},
menuActionIconContainer: {
width: 56,
height: 56,
borderRadius: 16,
backgroundColor: colors.chat.overlayQuote,
alignItems: 'center',
justifyContent: 'center',
marginBottom: 8,
},
menuActionLabel: {
fontSize: 13,
color: textPrimary,
fontWeight: '500',
},
// 取消按钮
menuCancelButton: {
backgroundColor: panelBgColor,
marginHorizontal: spacing.md,
paddingVertical: spacing.md,
borderRadius: 12,
alignItems: 'center',
},
menuCancelText: {
fontSize: 16,
color: textPrimary,
fontWeight: '600',
},
// QQ风格长按菜单
qqMenuOverlay: {
flex: 1,
backgroundColor: 'transparent',
},
qqMenuContainer: {
position: 'absolute',
backgroundColor: 'rgba(0, 0, 0, 0.9)',
borderRadius: 6,
paddingVertical: 6,
paddingHorizontal: 2,
shadowColor: colors.chat.shadow,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.3,
shadowRadius: 4,
elevation: 10,
},
qqMenuItemsRow: {
flexDirection: 'row',
alignItems: 'center',
},
qqMenuItem: {
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 10,
paddingVertical: 2,
minWidth: 52,
},
qqMenuItemWithBorder: {
borderRightWidth: 1,
borderRightColor: 'rgba(255, 255, 255, 0.15)',
},
qqMenuItemLabelContainer: {
marginTop: 4,
},
qqMenuItemLabel: {
fontSize: 11,
color: colors.primary.contrast,
fontWeight: '500',
},
// 回复预览(输入区)- 与气泡内引用同色条
replyPreviewContainer: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'rgba(74, 136, 199, 0.08)',
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
borderLeftWidth: 3,
borderLeftColor: colors.chat.link,
marginBottom: spacing.xs,
borderRadius: 8,
},
replyPreviewContent: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
replyPreviewText: {
flex: 1,
},
replyPreviewName: {
fontSize: 13,
color: colors.primary.main,
fontWeight: '600',
},
replyPreviewMessage: {
fontSize: 12,
color: colors.chat.textSecondary,
marginTop: 2,
},
replyPreviewClose: {
padding: 4,
},
// 遮罩层
overlay: {
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
alignItems: 'center',
justifyContent: 'center',
zIndex: 1000,
},
overlayContent: {
backgroundColor: cardBgColor,
padding: spacing.xl,
borderRadius: 16,
alignItems: 'center',
shadowColor: colors.chat.shadow,
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.15,
shadowRadius: 12,
elevation: 8,
},
overlayText: {
marginTop: spacing.md,
fontSize: 15,
color: colors.chat.textTertiary,
fontWeight: '500',
},
// 表情包添加按钮(管理界面第一位)
stickerAddButton: {
backgroundColor: cardBgColor,
borderWidth: 1.5,
borderColor: colors.primary.main,
borderStyle: 'dashed',
alignItems: 'center',
justifyContent: 'center',
},
stickerAddContent: {
alignItems: 'center',
justifyContent: 'center',
},
stickerAddText: {
fontSize: 11,
marginTop: 4,
fontWeight: '500',
},
// 表情包管理按钮(表情面板第一位)
stickerManageButton: {
backgroundColor: cardBgColor,
borderWidth: 1,
borderColor: colors.chat.border,
borderStyle: 'dashed',
alignItems: 'center',
justifyContent: 'center',
},
stickerManageContent: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
stickerManageText: {
fontSize: 12,
color: colors.chat.textTertiary,
marginTop: 4,
fontWeight: '500',
},
// 表情管理模态框2/3高度
manageModalOverlay: {
flex: 1,
justifyContent: 'flex-end',
},
manageModalBackdrop: {
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.4)',
},
manageModalHandle: {
width: 36,
height: 5,
borderRadius: 3,
backgroundColor: colors.chat.sheetGrip,
alignSelf: 'center',
marginTop: 8,
marginBottom: 4,
},
manageHeaderDivider: {
height: StyleSheet.hairlineWidth,
backgroundColor: colors.chat.borderHairline,
},
// 表情包选择状态
stickerItemSelected: {
borderWidth: 2,
borderColor: colors.chat.replyBorder,
},
stickerCheckOverlay: {
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(127, 182, 230, 0.14)',
alignItems: 'flex-end',
justifyContent: 'flex-start',
padding: 4,
},
stickerCheckBox: {
width: 22,
height: 22,
borderRadius: 11,
borderWidth: 2,
borderColor: colors.chat.card,
backgroundColor: 'rgba(255, 255, 255, 0.8)',
alignItems: 'center',
justifyContent: 'center',
},
stickerCheckBoxSelected: {
backgroundColor: colors.chat.replyBorder,
borderColor: colors.chat.replyBorder,
},
// 表情管理模态框
manageModalContainer: {
backgroundColor: panelBgColor,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
overflow: 'hidden',
},
manageModalHeader: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: spacing.md,
paddingVertical: spacing.md,
backgroundColor: cardBgColor,
borderBottomWidth: 1,
borderBottomColor: colors.chat.border,
},
manageHeaderButton: {
minWidth: 60,
alignItems: 'center',
},
manageModalTitle: {
fontSize: 17,
fontWeight: '600',
color: colors.chat.textPrimary,
},
manageDoneText: {
fontSize: 16,
color: colors.chat.link,
fontWeight: '500',
},
manageSelectText: {
fontSize: 16,
color: colors.chat.link,
fontWeight: '500',
},
manageInfoBar: {
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
backgroundColor: cardBgColor,
borderBottomWidth: 1,
borderBottomColor: colors.chat.border,
},
manageInfoText: {
fontSize: 13,
color: colors.chat.textSecondary,
},
manageStickerGrid: {
flex: 1,
paddingHorizontal: spacing.md,
paddingTop: spacing.md,
paddingBottom: spacing.xl,
},
manageBottomBar: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: spacing.md,
paddingVertical: spacing.md,
backgroundColor: cardBgColor,
borderTopWidth: 1,
borderTopColor: colors.chat.border,
paddingBottom: 34, // 安全区域
},
manageSelectAllButton: {
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
},
manageSelectAllText: {
fontSize: 15,
color: colors.chat.link,
fontWeight: '500',
},
manageDeleteButton: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.chat.danger,
paddingHorizontal: spacing.lg,
paddingVertical: spacing.sm + 2,
borderRadius: 20,
gap: 6,
},
manageDeleteButtonDisabled: {
backgroundColor: colors.chat.iconMuted,
},
manageDeleteText: {
fontSize: 15,
color: colors.primary.contrast,
fontWeight: '600',
},
manageTipBar: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
backgroundColor: colors.chat.tipBg,
gap: 6,
},
manageTipText: {
fontSize: 12,
color: colors.chat.textMuted,
},
// 管理界面空状态
manageEmptyContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: spacing.xl,
paddingVertical: spacing['4xl'],
},
manageEmptyIconBg: {
width: 88,
height: 88,
borderRadius: 44,
alignItems: 'center',
justifyContent: 'center',
marginBottom: spacing.lg,
},
manageEmptyTitle: {
fontSize: 17,
fontWeight: '600',
marginBottom: spacing.sm,
},
manageEmptyDesc: {
fontSize: 14,
textAlign: 'center',
},
});
}
export function useChatScreenStyles() {
const colors = useAppColors();
const dynamicStyles = useChatDynamicStyles();
return useMemo(() => createChatScreenStyles(colors, dynamicStyles), [colors, dynamicStyles]);
}