feat(ChatScreen): 优化聊天界面 UI 和交互体验
Made-with: Cursor
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
* 使用游标分页
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
Dimensions,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useLocalSearchParams } from 'expo-router';
|
||||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../theme';
|
||||
import { useAuthStore } from '../../stores';
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
IGroupMemberListPagedSource,
|
||||
} from '../../stores/groupMemberListSources';
|
||||
import { enrichGroupMembersWithUserProfiles } from '../../stores/groupMemberProfileResolver';
|
||||
import { Avatar, Text, Button, Loading, EmptyState, Divider, ResponsiveContainer } from '../../components/common';
|
||||
import { Avatar, Text, Button, Loading, EmptyState, Divider, ResponsiveContainer, AppBackButton } from '../../components/common';
|
||||
import { useResponsive, useBreakpointGTE } from '../../hooks/useResponsive';
|
||||
import { useCursorPagination } from '../../hooks/useCursorPagination';
|
||||
import {
|
||||
@@ -57,6 +57,7 @@ interface MemberGroup {
|
||||
const GroupMembersScreen: React.FC = () => {
|
||||
const colors = useAppColors();
|
||||
const styles = useMemo(() => createGroupMembersStyles(colors), [colors]);
|
||||
const router = useRouter();
|
||||
const { groupId: groupIdParam } = useLocalSearchParams<{ groupId?: string | string[] }>();
|
||||
const groupId = firstRouteParam(groupIdParam) ?? '';
|
||||
const { currentUser } = useAuthStore();
|
||||
@@ -149,11 +150,14 @@ const GroupMembersScreen: React.FC = () => {
|
||||
setLoading(false);
|
||||
}, [refresh]);
|
||||
|
||||
// 初始加载
|
||||
// 初始加载 - 使用 ref 避免依赖变化导致的无限循环
|
||||
const initialLoadRef = React.useRef(false);
|
||||
useEffect(() => {
|
||||
if (!groupId) return;
|
||||
if (!groupId || initialLoadRef.current) return;
|
||||
initialLoadRef.current = true;
|
||||
refresh();
|
||||
}, [groupId, refresh]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [groupId]);
|
||||
|
||||
// 按角色分组
|
||||
const groupMembers = useCallback((): MemberGroup[] => {
|
||||
@@ -640,7 +644,13 @@ const GroupMembersScreen: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container} edges={['bottom']}>
|
||||
<SafeAreaView style={styles.container} edges={['top', 'bottom']}>
|
||||
{/* Header */}
|
||||
<View style={styles.pageHeader}>
|
||||
<AppBackButton onPress={() => router.back()} />
|
||||
<Text variant="h3" style={styles.pageTitle}>群成员</Text>
|
||||
<View style={styles.pageHeaderPlaceholder} />
|
||||
</View>
|
||||
{loading ? <Loading /> : renderGroupedList()}
|
||||
{renderActionModal()}
|
||||
{renderNicknameModal()}
|
||||
@@ -654,6 +664,23 @@ function createGroupMembersStyles(colors: AppColors) {
|
||||
flex: 1,
|
||||
backgroundColor: colors.background.default,
|
||||
},
|
||||
// Header 样式
|
||||
pageHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingVertical: spacing.sm,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.divider,
|
||||
},
|
||||
pageTitle: {
|
||||
fontWeight: '600',
|
||||
},
|
||||
pageHeaderPlaceholder: {
|
||||
width: 40,
|
||||
},
|
||||
section: {
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user