Fix Git merge conflict in ConversationsScreen.tsx - combined both versions

This commit is contained in:
Bivekich
2025-08-06 11:29:25 +03:00
parent 1441440247
commit 1eea449a30

View File

@ -1,29 +1,20 @@
<<<<<<< HEAD
import React from 'react';
import { View, StyleSheet, FlatList, TouchableOpacity, Dimensions } from 'react-native';
import { List, Avatar, Text, FAB, Badge, Surface } from 'react-native-paper';
=======
import React, { useState } from 'react'; import React, { useState } from 'react';
import { View, StyleSheet, FlatList, TouchableOpacity } from 'react-native'; import { View, StyleSheet, FlatList, TouchableOpacity, Dimensions } from 'react-native';
import { List, Avatar, Text, FAB, Divider, Badge, Searchbar, IconButton, useTheme } from 'react-native-paper'; import { List, Avatar, Text, FAB, Divider, Badge, Searchbar, IconButton, useTheme } from 'react-native-paper';
>>>>>>> a3ad9832ae1663e2a76b50c417d43bcb23a0e03a
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import { GET_CONVERSATIONS } from '../graphql/queries'; import { GET_CONVERSATIONS } from '../graphql/queries';
import { Conversation } from '../types'; import { Conversation } from '../types';
import { format, isToday, isYesterday } from 'date-fns'; import { format, isToday, isYesterday } from 'date-fns';
import { ru } from 'date-fns/locale'; import { ru } from 'date-fns/locale';
<<<<<<< HEAD
import { LinearGradient } from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import Animated, { import Animated, {
FadeInDown, FadeInDown,
FadeInRight, FadeInRight,
Layout, Layout,
} from 'react-native-reanimated'; } from 'react-native-reanimated';
import { useAuth } from '../contexts/AuthContext';
const { width } = Dimensions.get('window'); const { width } = Dimensions.get('window');
=======
import { useAuth } from '../contexts/AuthContext';
>>>>>>> a3ad9832ae1663e2a76b50c417d43bcb23a0e03a
export const ConversationsScreen = ({ navigation }: any) => { export const ConversationsScreen = ({ navigation }: any) => {
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
@ -34,7 +25,6 @@ export const ConversationsScreen = ({ navigation }: any) => {
pollInterval: 5000, pollInterval: 5000,
}); });
<<<<<<< HEAD
const formatMessageTime = (date: string) => { const formatMessageTime = (date: string) => {
const messageDate = new Date(date); const messageDate = new Date(date);
if (isToday(messageDate)) { if (isToday(messageDate)) {
@ -46,9 +36,6 @@ export const ConversationsScreen = ({ navigation }: any) => {
} }
}; };
const renderConversation = ({ item, index }: { item: Conversation; index: number }) => {
const otherParticipant = item.participants.find(p => p.id !== data?.me?.id);
=======
// Фильтрация чатов по поисковому запросу // Фильтрация чатов по поисковому запросу
const filteredConversations = data?.conversations?.filter((conv: Conversation) => { const filteredConversations = data?.conversations?.filter((conv: Conversation) => {
if (!searchQuery) return true; if (!searchQuery) return true;
@ -60,9 +47,8 @@ export const ConversationsScreen = ({ navigation }: any) => {
conv.lastMessage?.content.toLowerCase().includes(searchQuery.toLowerCase()); conv.lastMessage?.content.toLowerCase().includes(searchQuery.toLowerCase());
}) || []; }) || [];
const renderConversation = ({ item }: { item: Conversation }) => { const renderConversation = ({ item, index }: { item: Conversation; index: number }) => {
const otherParticipant = item.participants.find(p => p.id !== user?.id); const otherParticipant = item.participants.find(p => p.id !== user?.id);
>>>>>>> a3ad9832ae1663e2a76b50c417d43bcb23a0e03a
const displayName = item.isGroup ? item.name : otherParticipant?.username; const displayName = item.isGroup ? item.name : otherParticipant?.username;
const lastMessageTime = item.lastMessage const lastMessageTime = item.lastMessage
? formatMessageTime(item.lastMessage.createdAt) ? formatMessageTime(item.lastMessage.createdAt)
@ -80,7 +66,7 @@ export const ConversationsScreen = ({ navigation }: any) => {
onPress={() => navigation.navigate('Chat', { conversationId: item.id, title: displayName })} onPress={() => navigation.navigate('Chat', { conversationId: item.id, title: displayName })}
activeOpacity={0.7} activeOpacity={0.7}
> >
<Surface style={styles.conversationItem} elevation={0}> <View style={[styles.conversationItem, { backgroundColor: theme.colors.surface }]}>
<View style={styles.avatarContainer}> <View style={styles.avatarContainer}>
<LinearGradient <LinearGradient
colors={['rgba(255,255,255,0.1)', 'rgba(255,255,255,0.05)']} colors={['rgba(255,255,255,0.1)', 'rgba(255,255,255,0.05)']}
@ -89,30 +75,24 @@ export const ConversationsScreen = ({ navigation }: any) => {
<Avatar.Text <Avatar.Text
size={52} size={52}
label={displayName?.charAt(0).toUpperCase() || '?'} label={displayName?.charAt(0).toUpperCase() || '?'}
style={styles.avatar} style={[styles.avatar, { backgroundColor: theme.colors.surfaceVariant }]}
labelStyle={styles.avatarLabel} labelStyle={[styles.avatarLabel, { color: theme.colors.onSurface }]}
theme={{
colors: {
primary: '#2d2d2d',
}
}}
/> />
{otherParticipant?.isOnline && ( {otherParticipant?.isOnline && (
<Badge style={styles.onlineBadge} size={14} /> <Badge style={styles.onlineBadge} size={14} />
)} )}
</View> </View>
<<<<<<< HEAD
<View style={styles.contentContainer}> <View style={styles.contentContainer}>
<View style={styles.headerRow}> <View style={styles.headerRow}>
<Text <Text
variant="titleMedium" variant="titleMedium"
style={styles.conversationTitle} style={[styles.conversationTitle, { color: theme.colors.onSurface }]}
numberOfLines={1} numberOfLines={1}
> >
{displayName || 'Без имени'} {displayName || 'Без имени'}
</Text> </Text>
<Text variant="bodySmall" style={styles.time}> <Text variant="bodySmall" style={[styles.time, { color: theme.colors.onSurfaceVariant }]}>
{lastMessageTime} {lastMessageTime}
</Text> </Text>
</View> </View>
@ -120,26 +100,17 @@ export const ConversationsScreen = ({ navigation }: any) => {
<View style={styles.messageRow}> <View style={styles.messageRow}>
<Text <Text
variant="bodyMedium" variant="bodyMedium"
style={styles.lastMessage} style={[styles.lastMessage, { color: theme.colors.onSurfaceVariant }]}
numberOfLines={2} numberOfLines={2}
> >
{item.lastMessage?.content || 'Нет сообщений'} {item.lastMessage?.content || 'Нет сообщений'}
</Text> </Text>
{/* Здесь можно добавить счетчик непрочитанных */} {unreadCount > 0 && (
<Badge style={styles.unreadBadge}>{unreadCount}</Badge>
)}
</View> </View>
=======
)}
right={() => (
<View style={styles.rightContent}>
<Text variant="bodySmall" style={styles.time}>
{lastMessageTime}
</Text>
{unreadCount > 0 && (
<Badge style={styles.unreadBadge}>{unreadCount}</Badge>
)}
>>>>>>> a3ad9832ae1663e2a76b50c417d43bcb23a0e03a
</View> </View>
</Surface> </View>
</TouchableOpacity> </TouchableOpacity>
</Animated.View> </Animated.View>
); );
@ -147,40 +118,38 @@ export const ConversationsScreen = ({ navigation }: any) => {
if (loading && !data) { if (loading && !data) {
return ( return (
<View style={styles.loadingContainer}> <View style={[styles.loadingContainer, { backgroundColor: theme.colors.background }]}>
<LinearGradient <LinearGradient
colors={['#0a0a0a', '#1a1a1a']} colors={[theme.colors.background, theme.colors.surface]}
style={StyleSheet.absoluteFillObject} style={StyleSheet.absoluteFillObject}
/> />
<Text style={styles.loadingText}>Загрузка чатов...</Text> <Text style={[styles.loadingText, { color: theme.colors.onSurfaceVariant }]}>Загрузка чатов...</Text>
</View> </View>
); );
} }
if (error) { if (error) {
return ( return (
<View style={styles.errorContainer}> <View style={[styles.errorContainer, { backgroundColor: theme.colors.background }]}>
<LinearGradient <LinearGradient
colors={['#0a0a0a', '#1a1a1a']} colors={[theme.colors.background, theme.colors.surface]}
style={StyleSheet.absoluteFillObject} style={StyleSheet.absoluteFillObject}
/> />
<Text style={styles.errorText}>Ошибка загрузки чатов</Text> <Text style={[styles.errorText, { color: theme.colors.error }]}>Ошибка загрузки чатов</Text>
<TouchableOpacity onPress={() => refetch()} style={styles.retryButton}> <TouchableOpacity onPress={() => refetch()} style={[styles.retryButton, { backgroundColor: theme.colors.surfaceVariant }]}>
<Text style={styles.retryText}>Попробовать снова</Text> <Text style={[styles.retryText, { color: theme.colors.onSurface }]}>Попробовать снова</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
); );
} }
return ( return (
<<<<<<< HEAD <View style={[styles.container, { backgroundColor: theme.colors.background }]}>
<View style={styles.container}>
<LinearGradient <LinearGradient
colors={['#0a0a0a', '#1a1a1a']} colors={[theme.colors.background, theme.colors.surface]}
style={StyleSheet.absoluteFillObject} style={StyleSheet.absoluteFillObject}
/> />
=======
<View style={[styles.container, { backgroundColor: theme.colors.background }]}>
{/* Поисковая строка */} {/* Поисковая строка */}
<View style={[styles.searchContainer, { backgroundColor: theme.colors.surface }]}> <View style={[styles.searchContainer, { backgroundColor: theme.colors.surface }]}>
<Searchbar <Searchbar
@ -192,7 +161,6 @@ export const ConversationsScreen = ({ navigation }: any) => {
/> />
</View> </View>
>>>>>>> a3ad9832ae1663e2a76b50c417d43bcb23a0e03a
<FlatList <FlatList
data={filteredConversations} data={filteredConversations}
renderItem={renderConversation} renderItem={renderConversation}
@ -201,51 +169,39 @@ export const ConversationsScreen = ({ navigation }: any) => {
refreshing={loading} refreshing={loading}
contentContainerStyle={styles.listContent} contentContainerStyle={styles.listContent}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
ItemSeparatorComponent={() => <View style={styles.separator} />} ItemSeparatorComponent={() => <View style={[styles.separator, { backgroundColor: theme.colors.outlineVariant }]} />}
ListEmptyComponent={ ListEmptyComponent={
<Animated.View <Animated.View
style={styles.emptyContainer} style={styles.emptyContainer}
entering={FadeInDown.duration(600)} entering={FadeInDown.duration(600)}
> >
<View style={styles.emptyIconContainer}> <View style={[styles.emptyIconContainer, { backgroundColor: theme.colors.surfaceVariant }]}>
<LinearGradient <LinearGradient
colors={['rgba(255,255,255,0.05)', 'rgba(255,255,255,0.02)']} colors={['rgba(255,255,255,0.05)', 'rgba(255,255,255,0.02)']}
style={styles.emptyIconGradient} style={styles.emptyIconGradient}
/> />
<Text style={styles.emptyIcon}>💬</Text> <Text style={styles.emptyIcon}>💬</Text>
</View> </View>
<Text variant="headlineSmall" style={styles.emptyText}> <Text variant="headlineSmall" style={[styles.emptyText, { color: theme.colors.onSurface }]}>
Нет активных чатов Нет активных чатов
</Text> </Text>
<Text variant="bodyLarge" style={styles.emptySubtext}> <Text variant="bodyLarge" style={[styles.emptySubtext, { color: theme.colors.onSurfaceVariant }]}>
Начните новый чат, нажав на кнопку внизу Начните новый чат, нажав на кнопку внизу
</Text> </Text>
</Animated.View> </Animated.View>
} }
/> />
<<<<<<< HEAD
<Animated.View <Animated.View
entering={FadeInRight.delay(300).springify()} entering={FadeInRight.delay(300).springify()}
> >
<FAB <FAB
icon="plus" icon="plus"
style={styles.fab} style={[styles.fab, { backgroundColor: theme.colors.primary }]}
onPress={() => navigation.navigate('NewChat')} onPress={() => navigation.navigate('Contacts')}
theme={{ color={theme.colors.onPrimary}
colors: {
primaryContainer: '#ffffff',
onPrimaryContainer: '#000000',
}
}}
/> />
</Animated.View> </Animated.View>
=======
<FAB
icon="plus"
style={styles.fab}
onPress={() => navigation.navigate('Contacts')}
/>
>>>>>>> a3ad9832ae1663e2a76b50c417d43bcb23a0e03a
</View> </View>
); );
}; };
@ -253,40 +209,29 @@ export const ConversationsScreen = ({ navigation }: any) => {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
backgroundColor: '#0a0a0a',
}, },
<<<<<<< HEAD
loadingContainer: { loadingContainer: {
======= flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
searchContainer: { searchContainer: {
padding: 16, padding: 16,
paddingBottom: 8, paddingBottom: 8,
backgroundColor: '#ffffff',
elevation: 2, elevation: 2,
}, },
searchbar: { searchbar: {
elevation: 0, elevation: 0,
backgroundColor: '#f5f5f5',
},
centerContainer: {
>>>>>>> a3ad9832ae1663e2a76b50c417d43bcb23a0e03a
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#0a0a0a',
}, },
loadingText: { loadingText: {
color: '#666666',
fontSize: 16, fontSize: 16,
}, },
errorContainer: { errorContainer: {
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
backgroundColor: '#0a0a0a',
}, },
errorText: { errorText: {
color: '#ff6b6b',
fontSize: 16, fontSize: 16,
marginBottom: 20, marginBottom: 20,
}, },
@ -294,10 +239,8 @@ const styles = StyleSheet.create({
paddingHorizontal: 24, paddingHorizontal: 24,
paddingVertical: 12, paddingVertical: 12,
borderRadius: 24, borderRadius: 24,
backgroundColor: 'rgba(255, 255, 255, 0.1)',
}, },
retryText: { retryText: {
color: '#ffffff',
fontSize: 14, fontSize: 14,
fontWeight: '600', fontWeight: '600',
}, },
@ -309,14 +252,12 @@ const styles = StyleSheet.create({
flexDirection: 'row', flexDirection: 'row',
paddingVertical: 16, paddingVertical: 16,
paddingHorizontal: 16, paddingHorizontal: 16,
backgroundColor: 'transparent',
marginHorizontal: 12, marginHorizontal: 12,
marginVertical: 4, marginVertical: 4,
borderRadius: 16, borderRadius: 16,
borderWidth: 1, borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.05)', borderColor: 'rgba(255, 255, 255, 0.05)',
}, },
<<<<<<< HEAD
avatarContainer: { avatarContainer: {
position: 'relative', position: 'relative',
marginRight: 12, marginRight: 12,
@ -331,20 +272,8 @@ const styles = StyleSheet.create({
backgroundColor: '#2d2d2d', backgroundColor: '#2d2d2d',
}, },
avatarLabel: { avatarLabel: {
color: '#ffffff',
fontSize: 20, fontSize: 20,
fontWeight: '600', fontWeight: '600',
=======
time: {
color: '#666',
fontSize: 12,
marginBottom: 4,
},
unreadBadge: {
backgroundColor: '#2196F3',
color: '#ffffff',
fontSize: 12,
>>>>>>> a3ad9832ae1663e2a76b50c417d43bcb23a0e03a
}, },
onlineBadge: { onlineBadge: {
position: 'absolute', position: 'absolute',
@ -365,13 +294,11 @@ const styles = StyleSheet.create({
marginBottom: 4, marginBottom: 4,
}, },
conversationTitle: { conversationTitle: {
color: '#ffffff',
fontWeight: '600', fontWeight: '600',
flex: 1, flex: 1,
marginRight: 12, marginRight: 12,
}, },
time: { time: {
color: '#666666',
fontSize: 12, fontSize: 12,
}, },
messageRow: { messageRow: {
@ -380,12 +307,15 @@ const styles = StyleSheet.create({
alignItems: 'center', alignItems: 'center',
}, },
lastMessage: { lastMessage: {
color: '#999999',
flex: 1, flex: 1,
}, },
unreadBadge: {
backgroundColor: '#2196F3',
color: '#ffffff',
fontSize: 12,
},
separator: { separator: {
height: 1, height: 1,
backgroundColor: 'rgba(255, 255, 255, 0.05)',
marginHorizontal: 28, marginHorizontal: 28,
marginVertical: 4, marginVertical: 4,
}, },
@ -394,10 +324,9 @@ const styles = StyleSheet.create({
margin: 16, margin: 16,
right: 0, right: 0,
bottom: 0, bottom: 0,
backgroundColor: '#ffffff',
borderRadius: 16, borderRadius: 16,
// iOS тени // iOS тени
shadowColor: '#ffffff', shadowColor: '#000',
shadowOffset: { shadowOffset: {
width: 0, width: 0,
height: 4, height: 4,
@ -421,7 +350,6 @@ const styles = StyleSheet.create({
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
marginBottom: 24, marginBottom: 24,
backgroundColor: 'rgba(255, 255, 255, 0.03)',
borderWidth: 1, borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.05)', borderColor: 'rgba(255, 255, 255, 0.05)',
}, },
@ -437,13 +365,11 @@ const styles = StyleSheet.create({
emptyText: { emptyText: {
textAlign: 'center', textAlign: 'center',
marginBottom: 12, marginBottom: 12,
color: '#ffffff',
fontWeight: '300', fontWeight: '300',
letterSpacing: 0.5, letterSpacing: 0.5,
}, },
emptySubtext: { emptySubtext: {
textAlign: 'center', textAlign: 'center',
color: '#666666',
maxWidth: 250, maxWidth: 250,
}, },
}); });