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

@@ -22,7 +22,7 @@ import { useAuthStore } from '../stores';
// Deep linking 配置
const linking: LinkingOptions<RootStackParamList> = {
prefixes: [],
prefixes: ['carrotbbs://'],
config: {
screens: {
Auth: {
@@ -63,6 +63,7 @@ const linking: LinkingOptions<RootStackParamList> = {
CreatePost: 'posts/create',
Chat: 'chat/:conversationId',
FollowList: 'users/:userId/:type',
QRCodeConfirm: 'qrcode/login/:sessionId',
},
},
};

View File

@@ -23,6 +23,7 @@ import { PostDetailScreen } from '../screens/home';
import { UserScreen } from '../screens/profile';
import FollowListScreen from '../screens/profile/FollowListScreen';
import { CreatePostScreen } from '../screens/create';
import { QRCodeConfirmScreen } from '../screens/auth/QRCodeConfirmScreen';
import {
ChatScreen,
CreateGroupScreen,
@@ -210,6 +211,15 @@ const getAuthenticatedScreens = () => [
animation: 'slide_from_right',
}}
/>,
<RootStack.Screen
key="QRCodeConfirm"
name="QRCodeConfirm"
component={QRCodeConfirmScreen}
options={{
headerShown: false,
presentation: 'modal',
}}
/>,
];
export function RootNavigator({ isAuthenticated, isInitializing }: RootNavigatorProps) {

View File

@@ -1,6 +1,6 @@
/**
* 简单的移动端 Tab Navigator
*
*
* 不使用 React Navigation 的 Tab Navigator而是使用一个简单的自定义实现
* 这样可以完全避免 React Navigation 状态恢复的问题
*/
@@ -15,6 +15,7 @@ import {
} from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { colors, shadows } from '../theme';
import { useTotalUnreadCount } from '../stores';
@@ -33,6 +34,15 @@ import { ProfileScreen, SettingsScreen, EditProfileScreen, NotificationSettingsS
// ==================== 类型定义 ====================
type TabName = 'HomeTab' | 'MessageTab' | 'ScheduleTab' | 'ProfileTab';
// Schedule Stack 类型定义
export type ScheduleStackParamList = {
Schedule: undefined;
CourseDetail: { course: any; relatedCourses?: any[] };
};
// ==================== Stack Navigators ====================
const ScheduleStack = createNativeStackNavigator<ScheduleStackParamList>();
// ==================== 常量 ====================
const TAB_BAR_HEIGHT = 64;
const TAB_BAR_MARGIN = 14;
@@ -41,19 +51,32 @@ const TAB_BAR_FLOATING_MARGIN = 12;
// ==================== 组件 ====================
/**
* 简化的 Stack Navigator 包装
* Schedule Stack Navigator 组件
*/
function SimpleStackNavigator({
children,
screenName
}: {
children: React.ReactNode;
screenName: string;
}) {
function ScheduleStackNavigatorComponent() {
return (
<View style={styles.stackContainer}>
{children}
</View>
<ScheduleStack.Navigator
screenOptions={{
headerShown: false,
}}
>
<ScheduleStack.Screen
name="Schedule"
component={ScheduleScreen}
options={{
title: '课表',
}}
/>
<ScheduleStack.Screen
name="CourseDetail"
component={CourseDetailScreen}
options={{
headerShown: false,
presentation: 'transparentModal',
animation: 'fade',
}}
/>
</ScheduleStack.Navigator>
);
}
@@ -83,7 +106,7 @@ export function SimpleMobileTabNavigator() {
case 'MessageTab':
return <MessageListScreen />;
case 'ScheduleTab':
return <ScheduleScreen />;
return <ScheduleStackNavigatorComponent />;
case 'ProfileTab':
return <ProfileScreen />;
default:

View File

@@ -106,6 +106,7 @@ export type RootStackParamList = {
userName?: string;
userAvatar?: string | null;
};
QRCodeConfirm: { sessionId: string };
};
// ==================== 全局类型声明 ====================