refactor(App, navigation): migrate to Expo Router and clean up navigation structure
- Updated App entry point to utilize Expo Router, simplifying the navigation setup. - Removed legacy navigation components and services to streamline the codebase. - Adjusted package.json to reflect the new entry point and updated dependencies for compatibility. - Enhanced overall application structure by consolidating navigation logic and improving maintainability.
This commit is contained in:
@@ -23,8 +23,7 @@ import {
|
||||
Clipboard,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { useNavigation, useRouter, useLocalSearchParams } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
import { colors, spacing, fontSizes, borderRadius } from '../../theme';
|
||||
@@ -35,19 +34,20 @@ import { postService, commentService, uploadService, authService, showPrompt, vo
|
||||
import { processPostUseCase } from '../../core/usecases/ProcessPostUseCase';
|
||||
import { useCursorPagination } from '../../hooks/useCursorPagination';
|
||||
import { CommentItem, VoteCard } from '../../components/business';
|
||||
import { Avatar, Button, Loading, EmptyState, Text, ImageGallery, ImageGrid, ImageGridItem, AdaptiveLayout } from '../../components/common';
|
||||
import { RootStackParamList } from '../../navigation/types';
|
||||
import { Avatar, Button, Loading, EmptyState, Text, ImageGallery, ImageGrid, ImageGridItem, AdaptiveLayout, AppBackButton } from '../../components/common';
|
||||
import { useResponsive, useResponsiveValue, useResponsiveSpacing } from '../../hooks/useResponsive';
|
||||
|
||||
type NavigationProp = NativeStackNavigationProp<RootStackParamList, 'PostDetail'>;
|
||||
type PostDetailRouteProp = RouteProp<RootStackParamList, 'PostDetail'>;
|
||||
import * as hrefs from '../../navigation/hrefs';
|
||||
|
||||
export const PostDetailScreen: React.FC = () => {
|
||||
const navigation = useNavigation<NavigationProp>();
|
||||
const route = useRoute<PostDetailRouteProp>();
|
||||
const navigation = useNavigation();
|
||||
const router = useRouter();
|
||||
const insets = useSafeAreaInsets();
|
||||
const postId = route.params?.postId || '';
|
||||
const shouldScrollToComments = route.params?.scrollToComments || false;
|
||||
const { postId: postIdParam, scrollToComments: scrollParam } = useLocalSearchParams<{
|
||||
postId?: string;
|
||||
scrollToComments?: string;
|
||||
}>();
|
||||
const postId = postIdParam || '';
|
||||
const shouldScrollToComments = scrollParam === '1' || scrollParam === 'true';
|
||||
|
||||
// 使用响应式 hook
|
||||
const {
|
||||
@@ -282,23 +282,18 @@ export const PostDetailScreen: React.FC = () => {
|
||||
|
||||
const author = post.author;
|
||||
const handleBackPress = () => {
|
||||
if (navigation.canGoBack()) {
|
||||
navigation.goBack();
|
||||
if (router.canGoBack()) {
|
||||
router.back();
|
||||
return;
|
||||
}
|
||||
navigation.navigate('Main', {
|
||||
screen: 'HomeTab',
|
||||
params: { screen: 'Home', params: undefined },
|
||||
});
|
||||
router.replace(hrefs.hrefHome());
|
||||
};
|
||||
|
||||
navigation.setOptions({
|
||||
headerBackVisible: false,
|
||||
headerTitleAlign: 'left',
|
||||
headerLeft: () => (
|
||||
<TouchableOpacity onPress={handleBackPress} style={styles.headerBackButton} hitSlop={8}>
|
||||
<MaterialCommunityIcons name="arrow-left" size={24} color={colors.text.primary} />
|
||||
</TouchableOpacity>
|
||||
<AppBackButton onPress={handleBackPress} style={styles.headerBackButton} />
|
||||
),
|
||||
headerTitle: () => (
|
||||
<View style={styles.headerContainer}>
|
||||
@@ -641,7 +636,7 @@ export const PostDetailScreen: React.FC = () => {
|
||||
Alert.alert('删除成功', '帖子已删除', [
|
||||
{
|
||||
text: '确定',
|
||||
onPress: () => navigation.goBack(),
|
||||
onPress: () => router.back(),
|
||||
},
|
||||
]);
|
||||
} catch (error) {
|
||||
@@ -654,15 +649,12 @@ export const PostDetailScreen: React.FC = () => {
|
||||
},
|
||||
],
|
||||
);
|
||||
}, [post, isDeleting, currentUser?.id, navigation]);
|
||||
}, [post, isDeleting, currentUser?.id, router]);
|
||||
|
||||
const handleEditPost = useCallback(() => {
|
||||
if (!post) return;
|
||||
navigation.navigate('CreatePost', {
|
||||
mode: 'edit',
|
||||
postId: post.id,
|
||||
});
|
||||
}, [navigation, post]);
|
||||
router.push(hrefs.hrefCreatePost('edit', post.id));
|
||||
}, [router, post]);
|
||||
|
||||
// 点击图片查看大图
|
||||
const handleImagePress = useCallback((images: ImageGridItem[], index: number) => {
|
||||
@@ -999,7 +991,7 @@ export const PostDetailScreen: React.FC = () => {
|
||||
|
||||
// 跳转到用户主页
|
||||
const handleUserPress = (userId: string) => {
|
||||
navigation.navigate('UserProfile', { userId });
|
||||
router.push(hrefs.hrefUserProfile(userId));
|
||||
};
|
||||
|
||||
// 渲染身份标识
|
||||
@@ -1294,27 +1286,22 @@ export const PostDetailScreen: React.FC = () => {
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* 评论标题 - 现代化设计 */}
|
||||
<View style={[styles.commentTitle, { paddingVertical: responsiveGap }]}>
|
||||
<View style={styles.commentTitleLeft}>
|
||||
<View style={[styles.commentTitleIconContainer, { width: isDesktop ? 32 : 28, height: isDesktop ? 32 : 28 }]}>
|
||||
<MaterialCommunityIcons
|
||||
name="chat-processing-outline"
|
||||
size={isDesktop ? 18 : 16}
|
||||
color={colors.primary.contrast}
|
||||
/>
|
||||
</View>
|
||||
<Text
|
||||
variant="body"
|
||||
style={[
|
||||
styles.commentTitleText,
|
||||
{ fontSize: isDesktop ? fontSizes.xl : fontSizes.lg }
|
||||
]}
|
||||
>
|
||||
评论
|
||||
</Text>
|
||||
<View style={styles.commentCountBadge}>
|
||||
<Text variant="caption" style={styles.commentCountText}>{post.comments_count}</Text>
|
||||
{/* 评论标题 - 现代化简洁分区头 */}
|
||||
<View style={[styles.commentSectionHeader, { marginTop: responsiveGap, marginBottom: responsiveGap }]}>
|
||||
<View style={styles.commentSectionTitleBlock}>
|
||||
<View style={styles.commentSectionTitleRow}>
|
||||
<Text
|
||||
variant="body"
|
||||
style={[
|
||||
styles.commentSectionTitle,
|
||||
{ fontSize: isDesktop ? fontSizes.xl : fontSizes.lg }
|
||||
]}
|
||||
>
|
||||
评论区
|
||||
</Text>
|
||||
<View style={styles.commentCountBadge}>
|
||||
<Text variant="caption" style={styles.commentCountText}>{post.comments_count}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
@@ -1396,9 +1383,9 @@ export const PostDetailScreen: React.FC = () => {
|
||||
<View style={styles.emptyCommentsContainer}>
|
||||
<View style={styles.emptyCommentsIconWrapper}>
|
||||
<MaterialCommunityIcons
|
||||
name="message-text-outline"
|
||||
size={isDesktop ? 48 : 40}
|
||||
color={colors.primary.main}
|
||||
name="message-reply-text-outline"
|
||||
size={isDesktop ? 24 : 22}
|
||||
color={colors.text.secondary}
|
||||
/>
|
||||
</View>
|
||||
<Text variant="body" style={styles.emptyCommentsTitle}>
|
||||
@@ -1831,7 +1818,7 @@ const styles = StyleSheet.create({
|
||||
postMetaInfo: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
justifyContent: 'flex-start',
|
||||
marginBottom: spacing.sm,
|
||||
},
|
||||
metaInfoMain: {
|
||||
@@ -1928,38 +1915,42 @@ const styles = StyleSheet.create({
|
||||
marginLeft: 6,
|
||||
fontWeight: '500',
|
||||
},
|
||||
commentTitle: {
|
||||
commentSectionHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: colors.divider,
|
||||
paddingTop: spacing.lg,
|
||||
},
|
||||
commentSectionTitleBlock: {
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
},
|
||||
commentSectionTitleRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
commentTitleLeft: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
commentTitleIconContainer: {
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.primary.main,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
commentTitleText: {
|
||||
fontWeight: '700',
|
||||
commentSectionTitle: {
|
||||
fontWeight: '800',
|
||||
color: colors.text.primary,
|
||||
letterSpacing: -0.2,
|
||||
},
|
||||
commentCountBadge: {
|
||||
backgroundColor: colors.primary.light + '25',
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: 2,
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.background.default,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: colors.divider,
|
||||
paddingHorizontal: spacing.sm + 2,
|
||||
paddingVertical: 3,
|
||||
borderRadius: 999,
|
||||
marginLeft: spacing.sm,
|
||||
minWidth: 24,
|
||||
alignItems: 'center',
|
||||
},
|
||||
commentCountText: {
|
||||
fontSize: fontSizes.sm,
|
||||
fontSize: fontSizes.xs,
|
||||
fontWeight: '700',
|
||||
color: colors.primary.main,
|
||||
color: colors.text.secondary,
|
||||
},
|
||||
inputContainer: {
|
||||
backgroundColor: colors.background.paper,
|
||||
@@ -2067,17 +2058,26 @@ const styles = StyleSheet.create({
|
||||
emptyCommentsContainer: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: spacing.xl * 2,
|
||||
marginHorizontal: spacing.lg,
|
||||
marginTop: spacing.lg,
|
||||
marginBottom: spacing.md,
|
||||
paddingVertical: spacing.xl + spacing.md,
|
||||
paddingHorizontal: spacing.lg,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: colors.divider,
|
||||
},
|
||||
emptyCommentsIconWrapper: {
|
||||
width: 72,
|
||||
height: 72,
|
||||
borderRadius: 36,
|
||||
backgroundColor: colors.primary.light + '18',
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 22,
|
||||
backgroundColor: colors.background.default,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: colors.divider,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: spacing.lg,
|
||||
marginBottom: spacing.sm,
|
||||
},
|
||||
emptyCommentsTitle: {
|
||||
fontSize: fontSizes.md,
|
||||
|
||||
Reference in New Issue
Block a user