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

@@ -4,7 +4,7 @@
* 支持响应式布局(宽屏下优化显示)
*/
import React, { useRef, useMemo } from 'react';
import React, { useRef, useMemo, useCallback } from 'react';
import {
View,
TouchableOpacity,
@@ -22,6 +22,14 @@ import { useResponsive, useBreakpointGTE } from '../../../../hooks/useResponsive
import { MessageBubbleProps, SenderInfo, MenuPosition, GroupMessage } from './types';
import { MessageSegmentsRenderer } from './SegmentRenderer';
import { MessageSegment, ImageSegmentData, extractTextFromSegments } from '../../../../types/dto';
import { SwipeableMessageBubble } from './SwipeableMessageBubble';
import {
getBubbleBorderRadius,
getMessageGroupPosition,
shouldShowSenderInfo,
bubbleColors,
bubbleStyles,
} from './bubbleStyles';
// 获取屏幕宽度
const { width: SCREEN_WIDTH } = Dimensions.get('window');
@@ -50,6 +58,7 @@ export const MessageBubble: React.FC<MessageBubbleProps> = ({
formatTime,
shouldShowTime,
onImagePress,
onReply,
}) => {
const bubbleRef = useRef<View>(null);
const pressPositionRef = useRef({ x: 0, y: 0 });
@@ -343,6 +352,13 @@ export const MessageBubble: React.FC<MessageBubbleProps> = ({
);
};
// 处理滑动回复
const handleSwipeReply = useCallback(() => {
if (onReply) {
onReply(message);
}
}, [onReply, message]);
// 系统通知消息渲染
if (isSystemNotice) {
return (
@@ -361,7 +377,8 @@ export const MessageBubble: React.FC<MessageBubbleProps> = ({
);
}
return (
// 消息内容渲染
const messageContent = (
<TouchableOpacity
onPressIn={handlePressIn}
onLongPress={handleLongPress}
@@ -444,6 +461,17 @@ export const MessageBubble: React.FC<MessageBubbleProps> = ({
</View>
</TouchableOpacity>
);
// 使用 SwipeableMessageBubble 包裹消息内容
return (
<SwipeableMessageBubble
isMe={isMe}
onReply={handleSwipeReply}
enabled={!!onReply}
>
{messageContent}
</SwipeableMessageBubble>
);
};
// Segment 消息的特殊样式 - 自适应宽度
@@ -460,4 +488,16 @@ const segmentStyles = StyleSheet.create({
},
});
export default MessageBubble;
// 使用 React.memo 优化渲染性能
export default React.memo(MessageBubble, (prevProps, nextProps) => {
// 自定义比较逻辑:只比较关键属性
return (
prevProps.message.id === nextProps.message.id &&
prevProps.message.status === nextProps.message.status &&
prevProps.selectedMessageId === nextProps.selectedMessageId &&
prevProps.currentUserId === nextProps.currentUserId &&
prevProps.isGroupChat === nextProps.isGroupChat &&
prevProps.otherUserLastReadSeq === nextProps.otherUserLastReadSeq &&
prevProps.index === nextProps.index
);
});