feat: add QR code login and enhance chat experience

- Add QR code login flow with scanner and confirmation screens
- Implement swipe-to-reply in chat with SwipeableMessageBubble
- Replace FlatList with FlashList for chat performance optimization
- Add Schedule stack navigator with CourseDetail screen support
- Configure deep linking for QR code login (carrotbbs://qrcode/login/:sessionId)
- Update branding from 胡萝卜 to 萝卜社区
- Display dynamic app version in settings
This commit is contained in:
lafay
2026-03-20 19:28:42 +08:00
parent 59877e6ae3
commit a005fb0a15
24 changed files with 2878 additions and 1859 deletions

View File

@@ -19,15 +19,15 @@
* - ChatInput.tsx: 输入框组件
*/
import React, { useState, useEffect, useMemo, useCallback } from 'react';
import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import {
View,
FlatList,
TouchableWithoutFeedback,
ActivityIndicator,
KeyboardAvoidingView,
Platform,
} from 'react-native';
import { FlashList } from "@shopify/flash-list";
import { useNavigation } from '@react-navigation/native';
import { StatusBar } from 'expo-status-bar';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -224,6 +224,7 @@ export const ChatScreen: React.FC = () => {
formatTime={formatTime}
shouldShowTime={shouldShowTime}
onImagePress={handleImagePress}
onReply={handleReplyMessage}
/>
);
@@ -268,25 +269,23 @@ export const ChatScreen: React.FC = () => {
<ActivityIndicator size="large" color={colors.primary.main} />
</View>
) : (
<FlatList
<FlashList
ref={flatListRef}
data={messages}
renderItem={renderMessage}
keyExtractor={item => String(item.id)}
contentContainerStyle={listContentStyle}
keyExtractor={(item: any) => String(item.id)}
contentContainerStyle={listContentStyle as any}
showsVerticalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
refreshing={loadingMore}
onRefresh={hasMoreHistory ? loadMoreHistory : undefined}
progressViewOffset={0}
onContentSizeChange={handleMessageListContentSizeChange}
// @ts-ignore FlashList 类型定义问题estimatedItemSize 是必需属性但类型定义缺失
estimatedItemSize={80}
maintainVisibleContentPosition={{
minIndexForVisible: 0,
autoscrollToTopThreshold: undefined,
} as any}
onScroll={handleMessageListScroll}
scrollEventThrottle={16}
// 优化渲染性能
initialNumToRender={15}
maxToRenderPerBatch={10}
windowSize={10}
removeClippedSubviews={true}
/>
)}
</View>