This commit is contained in:
imeepos
2026-01-29 16:42:42 +08:00
parent 1ccdc23355
commit a087cafc99
6 changed files with 553 additions and 80 deletions

View File

@@ -12,16 +12,18 @@ import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context'
import { useTranslation } from 'react-i18next'
import { useRouter, useFocusEffect } from 'expo-router'
import { PanGestureHandler } from 'react-native-gesture-handler'
import { useMessages, type Message } from '@/hooks/use-messages'
import { useMessageActions } from '@/hooks/use-message-actions'
import { useAnnouncements } from '@/hooks/use-announcements'
import { useSwipeNavigation } from '@/hooks/use-swipe-navigation'
import LoadingState from '@/components/LoadingState'
import ErrorState from '@/components/ErrorState'
import PaginationLoader from '@/components/PaginationLoader'
import { MessageCard } from '@/components/message/MessageCard'
import { MessageTabBar, type MessageType } from '@/components/message/MessageTabBar'
import { MessageTabBar, type MessageType, TAB_ITEMS } from '@/components/message/MessageTabBar'
import { AnnouncementBanner } from '@/components/message/AnnouncementBanner'
import { SwipeToDelete } from '@/components/message/SwipeToDelete'
import { MessageEmptyState } from '@/components/message/MessageEmptyState'
@@ -50,6 +52,9 @@ export default function MessageScreen() {
const router = useRouter()
const [activeTab, setActiveTab] = useState<MessageType>(undefined)
// 获取当前 Tab 索引
const activeTabIndex = TAB_ITEMS.findIndex(tab => tab.type === activeTab)
// Hooks
const {
messages: allMessages,
@@ -95,6 +100,26 @@ export default function MessageScreen() {
setActiveTab(type)
}, [])
// 左右滑动切换消息类型 Tab
const handleSwipeLeft = useCallback(() => {
if (activeTabIndex < TAB_ITEMS.length - 1) {
setActiveTab(TAB_ITEMS[activeTabIndex + 1].type)
}
}, [activeTabIndex])
const handleSwipeRight = useCallback(() => {
if (activeTabIndex > 0) {
setActiveTab(TAB_ITEMS[activeTabIndex - 1].type)
}
}, [activeTabIndex])
const { handleGestureEvent, handleGestureStateChange } = useSwipeNavigation({
onSwipeLeft: handleSwipeLeft,
onSwipeRight: handleSwipeRight,
canSwipeLeft: activeTabIndex < TAB_ITEMS.length - 1,
canSwipeRight: activeTabIndex > 0,
})
// Handle mark all read
const handleMarkAllRead = useCallback(async () => {
const unreadMessages = filteredMessages.filter(m => !m.isRead)
@@ -235,29 +260,37 @@ export default function MessageScreen() {
<MessageTabBar activeTab={activeTab} onTabChange={handleTabChange} />
{/* Message List */}
<FlatList
testID="message-list"
data={filteredMessages}
renderItem={renderMessageItem}
keyExtractor={(item) => item.id}
contentContainerStyle={[
styles.listContent,
filteredMessages.length === 0 && styles.emptyListContent,
]}
showsVerticalScrollIndicator={false}
onEndReached={handleEndReached}
onEndReachedThreshold={0.5}
ListFooterComponent={renderFooter}
ListEmptyComponent={renderEmptyComponent}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor="#FFFFFF"
colors={['#FFFFFF']}
<PanGestureHandler
onGestureEvent={handleGestureEvent}
onHandlerStateChange={handleGestureStateChange}
activeOffsetX={[-20, 20]}
>
<View style={styles.gestureContainer}>
<FlatList
testID="message-list"
data={filteredMessages}
renderItem={renderMessageItem}
keyExtractor={(item) => item.id}
contentContainerStyle={[
styles.listContent,
filteredMessages.length === 0 && styles.emptyListContent,
]}
showsVerticalScrollIndicator={false}
onEndReached={handleEndReached}
onEndReachedThreshold={0.5}
ListFooterComponent={renderFooter}
ListEmptyComponent={renderEmptyComponent}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor="#FFFFFF"
colors={['#FFFFFF']}
/>
}
/>
}
/>
</View>
</PanGestureHandler>
</SafeAreaView>
)
}
@@ -267,6 +300,9 @@ const styles = StyleSheet.create({
flex: 1,
backgroundColor: '#090A0B',
},
gestureContainer: {
flex: 1,
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',