feat(chat): implement dynamic theme support in chat components
- Enhanced ChatHeader and ChatInput components to support dynamic theme colors, improving visual consistency across different themes. - Updated styles in ChatScreen to utilize new dynamic styles for better responsiveness and user experience. - Refactored styles in various profile screens to adopt a unified background color scheme and improved spacing for a cleaner layout. This update significantly enhances the chat interface and profile settings by allowing for dynamic theming and improved visual elements.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* 聊天头部组件
|
||||
* 支持响应式布局(宽屏下显示更多信息)
|
||||
* 支持动态主题颜色
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
@@ -8,7 +9,7 @@ import { View, TouchableOpacity, StyleSheet } from 'react-native';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { Avatar, Text } from '../../../../components/common';
|
||||
import { useAppColors, spacing } from '../../../../theme';
|
||||
import { useChatScreenStyles } from './styles';
|
||||
import { useChatScreenStyles, useChatDynamicStyles } from './styles';
|
||||
import { useBreakpointGTE } from '../../../../hooks/useResponsive';
|
||||
import { ChatHeaderProps } from './types';
|
||||
|
||||
@@ -26,6 +27,7 @@ export const ChatHeader: React.FC<ChatHeaderProps> = ({
|
||||
}) => {
|
||||
const colors = useAppColors();
|
||||
const baseStyles = useChatScreenStyles();
|
||||
const dynamicStyles = useChatDynamicStyles();
|
||||
|
||||
// 响应式布局
|
||||
// 使用 768px 作为大屏幕和小屏幕的分界线
|
||||
@@ -33,6 +35,9 @@ export const ChatHeader: React.FC<ChatHeaderProps> = ({
|
||||
// 优先使用 props 传入的 isWideScreen,否则使用 hook
|
||||
const isWideScreen = propIsWideScreen !== undefined ? propIsWideScreen : isWideScreenHook;
|
||||
|
||||
// 动态图标颜色 - 使用主题色
|
||||
const iconColor = dynamicStyles.textPrimaryColor || colors.text.primary;
|
||||
|
||||
// 合并样式
|
||||
const styles = useMemo(() => {
|
||||
return StyleSheet.create({
|
||||
@@ -74,7 +79,7 @@ export const ChatHeader: React.FC<ChatHeaderProps> = ({
|
||||
<View style={styles.headerContainer}>
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity style={styles.backButton} onPress={onBack} activeOpacity={0.7}>
|
||||
<MaterialCommunityIcons name="chevron-left" size={28} color={colors.text.primary} />
|
||||
<MaterialCommunityIcons name="chevron-left" size={28} color={iconColor} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.headerCenter}>
|
||||
@@ -130,7 +135,7 @@ export const ChatHeader: React.FC<ChatHeaderProps> = ({
|
||||
onPress={onGroupInfoPress}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<MaterialCommunityIcons name="dots-horizontal" size={24} color={colors.text.primary} />
|
||||
<MaterialCommunityIcons name="dots-horizontal" size={24} color={iconColor} />
|
||||
</TouchableOpacity>
|
||||
) : (
|
||||
<TouchableOpacity
|
||||
@@ -138,7 +143,7 @@ export const ChatHeader: React.FC<ChatHeaderProps> = ({
|
||||
onPress={onMorePress}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<MaterialCommunityIcons name="dots-horizontal" size={24} color={colors.text.primary} />
|
||||
<MaterialCommunityIcons name="dots-horizontal" size={24} color={iconColor} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* 聊天输入框组件
|
||||
* 支持响应式布局(宽屏下居中显示)
|
||||
* 支持动态主题颜色
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
@@ -8,7 +9,7 @@ import { View, TouchableOpacity, TextInput, ActivityIndicator, ScrollView, Style
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { Text } from '../../../../components/common';
|
||||
import { useAppColors } from '../../../../theme';
|
||||
import { useChatScreenStyles } from './styles';
|
||||
import { useChatScreenStyles, useChatDynamicStyles } from './styles';
|
||||
import { useBreakpointGTE } from '../../../../hooks/useResponsive';
|
||||
import { ChatInputProps, GroupMessage, SenderInfo } from './types';
|
||||
import { extractTextFromSegments } from '../../../../types/dto';
|
||||
@@ -41,11 +42,18 @@ export const ChatInput: React.FC<ChatInputProps & {
|
||||
}) => {
|
||||
const colors = useAppColors();
|
||||
const styles = useChatScreenStyles();
|
||||
const dynamicStyles = useChatDynamicStyles();
|
||||
const isDisabled = isGroupChat && isMuted;
|
||||
|
||||
// 获取当前用户ID
|
||||
const currentUserId = currentUser?.id || '';
|
||||
|
||||
// 动态颜色
|
||||
const textPrimary = dynamicStyles.textPrimaryColor || colors.chat.textPrimary;
|
||||
const textSecondary = dynamicStyles.textSecondaryColor || colors.chat.textSecondary;
|
||||
const textMuted = '#999'; // 禁用状态颜色
|
||||
const textDisabled = '#CCC'; // 完全禁用颜色
|
||||
|
||||
// 响应式布局
|
||||
const isWideScreen = useBreakpointGTE('lg');
|
||||
|
||||
@@ -91,7 +99,7 @@ export const ChatInput: React.FC<ChatInputProps & {
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity onPress={onCancel} style={styles.replyPreviewClose}>
|
||||
<MaterialCommunityIcons name="close" size={18} color="#999" />
|
||||
<MaterialCommunityIcons name="close" size={18} color={textSecondary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
@@ -157,7 +165,7 @@ export const ChatInput: React.FC<ChatInputProps & {
|
||||
<MaterialCommunityIcons
|
||||
name={activePanel === 'emoji' ? "keyboard" : "emoticon-happy-outline"}
|
||||
size={26}
|
||||
color={isDisabled ? '#CCC' : (activePanel === 'emoji' ? colors.primary.main : '#666')}
|
||||
color={isDisabled ? textDisabled : (activePanel === 'emoji' ? colors.primary.main : textSecondary)}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
@@ -165,7 +173,7 @@ export const ChatInput: React.FC<ChatInputProps & {
|
||||
<TextInput
|
||||
style={[styles.input, isDisabled && styles.inputMuted]}
|
||||
placeholder={isGroupChat ? (isMuted ? (muteAll ? "全员禁言中..." : "你已被禁言...") : "发送消息,@提及成员...") : "发送消息..."}
|
||||
placeholderTextColor={isDisabled ? '#CCC' : '#999'}
|
||||
placeholderTextColor={isDisabled ? textDisabled : textMuted}
|
||||
value={inputText}
|
||||
onChangeText={onInputChange}
|
||||
multiline
|
||||
|
||||
@@ -25,25 +25,34 @@ 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: theme.bubble,
|
||||
// 夜间模式时使用系统暗色,否则使用主题色
|
||||
outgoingBubbleColor: isNightMode ? colors.chat.bubbleOutgoing : theme.bubble,
|
||||
// 背景色
|
||||
chatBackgroundColor: theme.secondary,
|
||||
chatBackgroundColor: isNightMode ? colors.chat.screen : theme.secondary,
|
||||
// 卡片/头部背景色
|
||||
cardBackgroundColor: theme.card,
|
||||
cardBackgroundColor: isNightMode ? colors.chat.card : theme.card,
|
||||
// 输入框背景色
|
||||
inputBackgroundColor: theme.inputBg,
|
||||
inputBackgroundColor: isNightMode ? colors.chat.surfaceRaised : theme.inputBg,
|
||||
// 面板背景色
|
||||
panelBackgroundColor: theme.panelBg,
|
||||
panelBackgroundColor: isNightMode ? colors.chat.surfaceMuted : theme.panelBg,
|
||||
// 主要文字颜色
|
||||
textPrimaryColor: theme.textPrimary,
|
||||
textPrimaryColor: isNightMode ? colors.chat.textPrimary : theme.textPrimary,
|
||||
// 次要文字颜色
|
||||
textSecondaryColor: theme.textSecondary,
|
||||
textSecondaryColor: isNightMode ? colors.chat.textSecondary : theme.textSecondary,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user