expo-popcore-app/app/(tabs)/_layout.tsx

183 lines
5.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Tabs } from 'expo-router'
import React, { useEffect } from 'react'
import { StyleSheet, View, Text, Platform } from 'react-native'
import { LinearGradient } from 'expo-linear-gradient'
import { useTranslation } from 'react-i18next'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { HomeIcon, MessageIcon, MyIcon, VideoIcon } from '@/components/icon'
import { useMessageUnreadCount } from '@/hooks/use-message-unread-count'
import { useAnnouncementUnreadCount } from '@/hooks/use-announcement-unread-count'
const TAB_BAR_HEIGHT = 80
export default function TabLayout() {
const { t } = useTranslation()
const insets = useSafeAreaInsets()
// Android 不需要额外的底部安全区域iOS 和 Web 需要
const bottomInset = Platform.OS === 'android' ? 0 : insets.bottom
// 获取未读消息数和公告数
const { data: messageData, refetch: refetchMessages } = useMessageUnreadCount()
const { data: announcementData, refetch: refetchAnnouncements } = useAnnouncementUnreadCount()
// 计算总未读数
const totalUnreadCount = (messageData?.total || 0) + (announcementData?.count || 0)
// 组件挂载时获取未读数
useEffect(() => {
refetchMessages()
refetchAnnouncements()
}, [])
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: '#FFFFFF',
tabBarInactiveTintColor: '#FFFFFF',
headerShown: false,
tabBarHideOnKeyboard: true,
tabBarShowLabel: true,
tabBarStyle: {
position: 'absolute',
backgroundColor: '#1C1E22',
height: TAB_BAR_HEIGHT + bottomInset,
paddingTop: 4,
paddingBottom: bottomInset,
paddingLeft: 4,
paddingRight: 4,
borderTopWidth: 0,
elevation: 0,
shadowOpacity: 0,
borderTopColor: 'transparent',
},
tabBarLabelStyle: {
color: '#FFFFFF',
fontSize: 10,
fontWeight: '400',
},
tabBarBackground: () => (
<View style={{ flex: 1, backgroundColor: '#1C1E22' }} />
),
}}
>
<Tabs.Screen
name="index"
options={{
title: t('tabs.home'),
tabBarLabel: ({ focused }: { focused: boolean }) => (focused ? null : <Text style={styles.tabLabel}>{t('tabs.home')}</Text>),
tabBarIcon: ({ focused }: { focused: boolean }) => {
if (focused) {
return (
<LinearGradient colors={['#9966FF', '#FF6699', '#FF9966']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.iconContainer}>
<HomeIcon />
</LinearGradient>
)
}
return (
<View style={{ opacity: 0.6 }}>
<HomeIcon />
</View>
)
},
}}
/>
<Tabs.Screen
name="video"
options={{
title: t('tabs.video'),
tabBarLabel: ({ focused }: { focused: boolean }) => (focused ? null : <Text style={styles.tabLabel}>{t('tabs.video')}</Text>),
tabBarIcon: ({ focused }: { focused: boolean }) => {
if (focused) {
return (
<LinearGradient colors={['#9966FF', '#FF6699', '#FF9966']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.iconContainer}>
<VideoIcon />
</LinearGradient>
)
}
return (
<View style={{ opacity: 0.6 }}>
<VideoIcon />
</View>
)
},
}}
/>
<Tabs.Screen
name="message"
options={{
title: t('tabs.message'),
tabBarLabel: ({ focused }: { focused: boolean }) => (focused ? null : <Text style={styles.tabLabel}>{t('tabs.message')}</Text>),
tabBarIcon: ({ focused }: { focused: boolean }) => {
if (focused) {
return (
<View>
<LinearGradient colors={['#9966FF', '#FF6699', '#FF9966']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.iconContainer}>
<MessageIcon />
</LinearGradient>
{totalUnreadCount > 0 && (
<View testID="message-unread-badge" style={styles.unreadBadge} />
)}
</View>
)
}
return (
<View style={{ opacity: focused ? 1 : 0.6 }}>
<MessageIcon />
{totalUnreadCount > 0 && (
<View testID="message-unread-badge" style={styles.unreadBadge} />
)}
</View>
)
},
}}
/>
<Tabs.Screen
name="my"
options={{
title: t('tabs.my'),
tabBarLabel: ({ focused }: { focused: boolean }) => (focused ? null : <Text style={styles.tabLabel}>{t('tabs.my')}</Text>),
tabBarIcon: ({ focused }: { focused: boolean }) => {
if (focused) {
return (
<LinearGradient colors={['#9966FF', '#FF6699', '#FF9966']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.iconContainer}>
<MyIcon />
</LinearGradient>
)
}
return (
<View style={{ opacity: focused ? 1 : 0.6 }}>
<MyIcon />
</View>
)
},
}}
/>
</Tabs>
)
}
const styles = StyleSheet.create({
iconContainer: {
width: 87,
height: 41,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 100,
},
tabLabel: {
fontSize: 10,
color: '#FFFFFF',
textAlign: 'center',
},
unreadBadge: {
position: 'absolute',
top: 0,
right: 0,
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: '#00FF66',
},
})