- Update design tokens with dark gaming theme (OLED-friendly) - Pure black backgrounds (#000000) - Cyan primary (#00d9ff) and neon green accent (#00ff88) - Glassmorphism effects and mobile-specific tokens - Build complete React Native mobile app screens - HomeScreen: Chat list with dark cards and status indicators - MessagesScreen: Chat view with gradient bubbles and typing indicators - FriendsScreen: Friend list with online/offline sections and game presence - GamesScreen: GameForge projects with team channels - ProfileScreen: User profile with .aethex domain display - AppNavigator: Bottom tab navigation with glow effects - Create Astro marketing landing site - Hero section with animated gradients and phone mockup - Features showcase (6 cards) - Pricing tiers (Free/Premium/Enterprise) - Download section for all platforms - Fully responsive dark theme Design inspiration: BitChat, Root, Discord Dark, Telegram Mobile-first approach with 48px touch targets and safe areas
222 lines
5.9 KiB
TypeScript
222 lines
5.9 KiB
TypeScript
/**
|
||
* Friends Screen
|
||
* Cross-game friends list with status
|
||
*/
|
||
|
||
import React, { useState } from 'react';
|
||
import {
|
||
View,
|
||
Text,
|
||
StyleSheet,
|
||
FlatList,
|
||
TouchableOpacity,
|
||
SafeAreaView,
|
||
SectionList,
|
||
} from 'react-native';
|
||
import { theme } from '../theme';
|
||
|
||
interface Friend {
|
||
id: string;
|
||
username: string;
|
||
status: 'online' | 'offline' | 'idle' | 'dnd';
|
||
game?: string;
|
||
avatar: string;
|
||
}
|
||
|
||
export default function FriendsScreen({ navigation }: any) {
|
||
const [friends] = useState<Friend[]>([
|
||
{ id: '1', username: 'john.aethex', status: 'online', game: 'Valorant', avatar: 'J' },
|
||
{ id: '2', username: 'sarah.aethex', status: 'online', game: 'Fortnite', avatar: 'S' },
|
||
{ id: '3', username: 'mike.aethex', status: 'idle', avatar: 'M' },
|
||
{ id: '4', username: 'alex.aethex', status: 'offline', avatar: 'A' },
|
||
]);
|
||
|
||
const onlineFriends = friends.filter(f => f.status === 'online');
|
||
const offlineFriends = friends.filter(f => f.status !== 'online');
|
||
|
||
const sections = [
|
||
{ title: `ONLINE (${onlineFriends.length})`, data: onlineFriends },
|
||
{ title: `OFFLINE (${offlineFriends.length})`, data: offlineFriends },
|
||
];
|
||
|
||
const getStatusColor = (status: Friend['status']) => {
|
||
switch (status) {
|
||
case 'online': return theme.colors.online;
|
||
case 'idle': return theme.colors.idle;
|
||
case 'dnd': return theme.colors.dnd;
|
||
default: return theme.colors.offline;
|
||
}
|
||
};
|
||
|
||
const renderFriend = ({ item }: { item: Friend }) => (
|
||
<TouchableOpacity style={styles.friendCard} activeOpacity={0.7}>
|
||
<View style={styles.avatarContainer}>
|
||
<View style={styles.avatar}>
|
||
<Text style={styles.avatarText}>{item.avatar}</Text>
|
||
</View>
|
||
<View style={[styles.statusDot, { backgroundColor: getStatusColor(item.status) }]} />
|
||
</View>
|
||
<View style={styles.friendInfo}>
|
||
<Text style={styles.username}>{item.username}</Text>
|
||
{item.game && (
|
||
<View style={styles.gameRow}>
|
||
<Text style={styles.gameIcon}>🎮</Text>
|
||
<Text style={styles.gameText}>Playing {item.game}</Text>
|
||
</View>
|
||
)}
|
||
{!item.game && item.status === 'offline' && (
|
||
<Text style={styles.lastSeen}>Last seen 2h ago</Text>
|
||
)}
|
||
</View>
|
||
<View style={styles.actions}>
|
||
<TouchableOpacity style={styles.actionButton}>
|
||
<Text style={styles.actionIcon}>💬</Text>
|
||
</TouchableOpacity>
|
||
{item.status === 'online' && (
|
||
<TouchableOpacity style={styles.actionButton}>
|
||
<Text style={styles.actionIcon}>📞</Text>
|
||
</TouchableOpacity>
|
||
)}
|
||
</View>
|
||
</TouchableOpacity>
|
||
);
|
||
|
||
return (
|
||
<SafeAreaView style={styles.container}>
|
||
<View style={styles.header}>
|
||
<Text style={styles.headerTitle}>Friends</Text>
|
||
<TouchableOpacity style={styles.addButton}>
|
||
<Text style={styles.addIcon}>➕</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
|
||
<SectionList
|
||
sections={sections}
|
||
renderItem={renderFriend}
|
||
renderSectionHeader={({ section }) => (
|
||
<View style={styles.sectionHeader}>
|
||
<Text style={styles.sectionTitle}>{section.title}</Text>
|
||
</View>
|
||
)}
|
||
keyExtractor={(item) => item.id}
|
||
contentContainerStyle={styles.listContent}
|
||
stickySectionHeadersEnabled={false}
|
||
/>
|
||
</SafeAreaView>
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
container: {
|
||
flex: 1,
|
||
backgroundColor: theme.colors.background,
|
||
},
|
||
header: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
paddingHorizontal: theme.spacing.md,
|
||
paddingVertical: theme.spacing.md,
|
||
},
|
||
headerTitle: {
|
||
fontSize: theme.typography.fontSize.xxl,
|
||
fontWeight: theme.typography.fontWeight.bold,
|
||
color: theme.colors.text,
|
||
},
|
||
addButton: {
|
||
width: theme.layout.touchTarget,
|
||
height: theme.layout.touchTarget,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
addIcon: {
|
||
fontSize: 24,
|
||
},
|
||
listContent: {
|
||
paddingHorizontal: theme.spacing.md,
|
||
},
|
||
sectionHeader: {
|
||
paddingVertical: theme.spacing.md,
|
||
},
|
||
sectionTitle: {
|
||
fontSize: theme.typography.fontSize.sm,
|
||
fontWeight: theme.typography.fontWeight.semibold,
|
||
color: theme.colors.textTertiary,
|
||
letterSpacing: 0.5,
|
||
},
|
||
friendCard: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
backgroundColor: theme.colors.card,
|
||
borderRadius: theme.borderRadius.lg,
|
||
padding: theme.spacing.md,
|
||
marginBottom: theme.spacing.md,
|
||
borderWidth: 1,
|
||
borderColor: 'rgba(255, 255, 255, 0.05)',
|
||
},
|
||
avatarContainer: {
|
||
position: 'relative',
|
||
marginRight: theme.spacing.md,
|
||
},
|
||
avatar: {
|
||
width: 48,
|
||
height: 48,
|
||
borderRadius: theme.borderRadius.full,
|
||
backgroundColor: theme.colors.primary,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
avatarText: {
|
||
fontSize: 20,
|
||
fontWeight: theme.typography.fontWeight.bold,
|
||
color: '#000',
|
||
},
|
||
statusDot: {
|
||
position: 'absolute',
|
||
bottom: 0,
|
||
right: 0,
|
||
width: 14,
|
||
height: 14,
|
||
borderRadius: 7,
|
||
borderWidth: 2,
|
||
borderColor: theme.colors.card,
|
||
},
|
||
friendInfo: {
|
||
flex: 1,
|
||
},
|
||
username: {
|
||
fontSize: theme.typography.fontSize.base,
|
||
fontWeight: theme.typography.fontWeight.semibold,
|
||
color: theme.colors.text,
|
||
marginBottom: 4,
|
||
},
|
||
gameRow: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
},
|
||
gameIcon: {
|
||
fontSize: 14,
|
||
marginRight: 4,
|
||
},
|
||
gameText: {
|
||
fontSize: theme.typography.fontSize.sm,
|
||
color: theme.colors.textSecondary,
|
||
},
|
||
lastSeen: {
|
||
fontSize: theme.typography.fontSize.sm,
|
||
color: theme.colors.textTertiary,
|
||
},
|
||
actions: {
|
||
flexDirection: 'row',
|
||
},
|
||
actionButton: {
|
||
width: 40,
|
||
height: 40,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
marginLeft: theme.spacing.sm,
|
||
},
|
||
actionIcon: {
|
||
fontSize: 20,
|
||
},
|
||
});
|