Files
frontend/src/screens/message/components/ChatScreen/ChatHeader.tsx
lafay b49cc0f3bd
All checks were successful
Frontend CI / build-and-push-web (push) Successful in 3m4s
Frontend CI / ota-android (push) Successful in 12m24s
Frontend CI / build-android-apk (push) Successful in 1h17m36s
refactor(TabsLayout, ImageGallery, ChatScreen, GroupInfoScreen, PrivateChatInfoScreen): enhance UI components and improve layout structure
- Adjusted tab bar dimensions and margins in TabsLayout for better visual consistency.
- Streamlined ImageGallery by removing loading states and optimizing image transition handling.
- Updated ChatScreen to utilize SafeAreaView for improved layout on different devices.
- Enhanced GroupInfoScreen and PrivateChatInfoScreen with a consistent page header layout, including back navigation.
- Refactored ChatHeader to simplify structure and improve maintainability.
2026-03-24 15:39:28 +08:00

138 lines
4.5 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.
/**
* 聊天头部组件
* 支持响应式布局(宽屏下显示更多信息)
*/
import React, { useMemo } from 'react';
import { View, TouchableOpacity, StyleSheet } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { Avatar, Text, AppBackButton } from '../../../../components/common';
import { colors, spacing } from '../../../../theme';
import { chatScreenStyles as baseStyles } from './styles';
import { useBreakpointGTE } from '../../../../hooks/useResponsive';
import { ChatHeaderProps } from './types';
export const ChatHeader: React.FC<ChatHeaderProps> = ({
isGroupChat,
groupInfo,
otherUser,
routeGroupName,
typingHint,
onBack,
onTitlePress,
onMorePress,
onGroupInfoPress,
isWideScreen: propIsWideScreen,
}) => {
// 响应式布局
// 使用 768px 作为大屏幕和小屏幕的分界线
const isWideScreenHook = useBreakpointGTE('lg');
// 优先使用 props 传入的 isWideScreen否则使用 hook
const isWideScreen = propIsWideScreen !== undefined ? propIsWideScreen : isWideScreenHook;
// 合并样式
const styles = useMemo(() => {
return StyleSheet.create({
...baseStyles,
headerContainer: {
...baseStyles.headerContainer,
maxWidth: isWideScreen ? 1200 : undefined,
alignSelf: isWideScreen ? 'center' : undefined,
width: isWideScreen ? '100%' : undefined,
},
header: {
...baseStyles.header,
paddingHorizontal: isWideScreen ? spacing.xl : spacing.md,
},
headerName: {
...baseStyles.headerName,
fontSize: isWideScreen ? 19 : 17,
},
memberCount: {
...baseStyles.memberCount,
fontSize: isWideScreen ? 14 : 13,
},
typingHint: {
...baseStyles.typingHint,
fontSize: isWideScreen ? 13 : 12,
},
});
}, [isWideScreen]);
// 获取显示标题
const getDisplayTitle = () => {
if (isGroupChat) {
return routeGroupName || groupInfo?.name || '群聊';
}
return otherUser?.nickname || '用户';
};
return (
<View style={styles.headerContainer}>
<View style={styles.header}>
<AppBackButton style={styles.backButton} onPress={onBack} />
<View style={styles.headerCenter}>
<TouchableOpacity
style={styles.titleRow}
onPress={onTitlePress}
activeOpacity={0.75}
>
{isGroupChat ? (
<>
<View style={styles.titleLeading}>
<MaterialCommunityIcons name="account-group" size={20} color={colors.primary.main} />
</View>
<View style={styles.titleContent}>
<Text style={styles.headerName} numberOfLines={1}>{getDisplayTitle()}</Text>
<View style={styles.subtitleRow}>
<Text style={styles.memberCount}>{groupInfo?.member_count || 0}</Text>
{typingHint && (
<Text style={styles.typingHint} numberOfLines={1}>{typingHint}</Text>
)}
</View>
</View>
</>
) : (
<>
<Avatar
source={otherUser?.avatar || null}
size={32}
name={otherUser?.nickname || ''}
/>
<View style={styles.titleContent}>
<Text style={styles.headerName} numberOfLines={1}>{getDisplayTitle()}</Text>
{typingHint && (
<View style={styles.subtitleRow}>
<Text style={styles.typingHint} numberOfLines={1}>{typingHint}</Text>
</View>
)}
</View>
</>
)}
</TouchableOpacity>
</View>
{/* 大屏幕 + 群聊时显示群信息按钮,否则显示三点菜单 */}
{isWideScreen && isGroupChat && onGroupInfoPress ? (
<TouchableOpacity
style={styles.moreButton}
onPress={onGroupInfoPress}
>
<MaterialCommunityIcons name="dots-horizontal" size={22} color={colors.text.primary} />
</TouchableOpacity>
) : (
<TouchableOpacity
style={styles.moreButton}
onPress={onMorePress}
>
<MaterialCommunityIcons name="dots-horizontal" size={22} color={colors.text.primary} />
</TouchableOpacity>
)}
</View>
</View>
);
};
export default ChatHeader;