import { Pressable, View, Dimensions } from 'react-native';
import { Image } from 'expo-image';
import { router } from 'expo-router';
import ContextMenu from 'react-native-context-menu-view';
import { Ionicons } from '@expo/vector-icons';
import { useTheme } from '~/contexts/ThemeContext';
import { Text } from '~/components/Text';
import { Button } from '~/components/Button';
import { Tag } from '~/store/tagStore';
import { usePromptStore } from '~/store/promptStore';
import { LAYOUT } from '~/constants';
import { getThumbnailUrl, getSizeForViewMode } from '~/utils/image';
const { width } = Dimensions.get('window');
type ImageCardProps = {
id: string;
publicUrl: string | null;
prompt: string;
createdAt: string;
isFavorite?: boolean;
model?: string;
tags?: Tag[];
viewMode: 'single' | 'grid3' | 'grid5';
blurhash?: string | null;
isGenerating?: boolean; // New prop for generating state
// Gallery mode props
onToggleFavorite?: () => void;
// Explore mode props
creatorUsername?: string;
likesCount?: number;
userHasLiked?: boolean;
onToggleLike?: () => void;
};
export function ImageCard({
id,
publicUrl,
prompt,
createdAt,
isFavorite,
model,
tags,
viewMode,
blurhash,
isGenerating,
onToggleFavorite,
creatorUsername,
likesCount,
userHasLiked,
onToggleLike,
}: ImageCardProps) {
const { theme } = useTheme();
const { setPrompt } = usePromptStore();
const isSingleColumn = viewMode === 'single';
const isGalleryMode = !!onToggleFavorite;
// Get appropriate thumbnail URL based on view mode
const thumbnailUrl = getThumbnailUrl(publicUrl, getSizeForViewMode(viewMode));
// Get tiny thumbnail for progressive loading (blur-up effect)
const tinyThumbnailUrl = getThumbnailUrl(publicUrl, 'tiny');
// Calculate image size based on view mode
const getImageSize = () => {
const spacing = 4; // Minimal spacing between items
switch (viewMode) {
case 'single':
return width - spacing * 2; // Minimal outer padding
case 'grid3':
return (width - spacing * 4) / 3; // Left + right + 2 gaps
case 'grid5':
return (width - spacing * 6) / 5; // Left + right + 4 gaps
default:
return width - spacing * 2;
}
};
const imageSize = getImageSize();
// Format model name for display
const formatModelName = (modelName?: string) => {
if (!modelName) return 'Unbekannt';
// Remove common prefixes and clean up
const cleaned = modelName
.replace(/^(black-forest-labs\/|bytedance\/|lucataco\/|stability-ai\/)/, '')
.replace(/-/g, ' ')
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
return cleaned;
};
// Context menu actions
const contextMenuActions = isGalleryMode ? [
{
title: isFavorite ? 'Von Favoriten entfernen' : 'Zu Favoriten hinzufügen',
systemIcon: isFavorite ? 'heart.fill' : 'heart',
},
{
title: 'Teilen',
systemIcon: 'square.and.arrow.up',
},
{
title: 'Details anzeigen',
systemIcon: 'info.circle',
},
{
title: new Date(createdAt).toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
}),
systemIcon: 'calendar',
disabled: true,
},
{
title: formatModelName(model),
systemIcon: 'cpu',
disabled: true,
},
] : [
// Explore mode actions
{
title: userHasLiked ? 'Like entfernen' : 'Liken',
systemIcon: userHasLiked ? 'heart.fill' : 'heart',
},
{
title: 'Teilen',
systemIcon: 'square.and.arrow.up',
},
{
title: 'Details anzeigen',
systemIcon: 'info.circle',
},
{
title: `von ${creatorUsername || 'Anonym'}`,
systemIcon: 'person',
disabled: true,
},
{
title: new Date(createdAt).toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
}),
systemIcon: 'calendar',
disabled: true,
},
{
title: formatModelName(model),
systemIcon: 'cpu',
disabled: true,
},
];
const handleContextMenu = (e: any) => {
const index = e.nativeEvent.index;
if (isGalleryMode) {
switch (index) {
case 0: // Toggle favorite
onToggleFavorite?.();
break;
case 1: // Share
// TODO: Implement share functionality
console.log('Share image:', id);
break;
case 2: // View details
router.push(`/image/${id}`);
break;
}
} else {
// Explore mode
switch (index) {
case 0: // Toggle like
onToggleLike?.();
break;
case 1: // Share
// TODO: Implement share functionality
console.log('Share image:', id);
break;
case 2: // View details
router.push(`/image/${id}`);
break;
}
}
};
const CardContent = isSingleColumn ? (
// Single Column: Image and info as separate elements
router.push(`/image/${id}`)}
>
{/* Image Container */}
{/* Show loading state for generating images */}
{isGenerating ? (
Generiere...
) : thumbnailUrl ? (
) : (
{prompt.substring(0, 50)}...
)}
{/* Info below image - outside the image container */}
{/* Prompt with Author/Favorite/Likes */}
{
if (isGalleryMode) {
e.stopPropagation();
setPrompt(prompt);
}
}}
style={{ flex: 1, marginRight: 8 }}
>
{prompt}
{/* Gallery Mode: Favorite Badge */}
{isGalleryMode && isFavorite && (
)}
{/* Explore Mode: Author Name and Likes */}
{!isGalleryMode && (
{creatorUsername || 'Anonym'}
)}
) : (
// Grid View: Original layout with overlays
router.push(`/image/${id}`)}
>
{/* Show loading state for generating images */}
{isGenerating ? (
{viewMode !== 'grid5' && (
Generiere...
)}
) : thumbnailUrl ? (
) : (
{prompt.substring(0, 50)}...
)}
{/* Explore Mode Grid: Creator and Like Info - hide in grid5 */}
{!isGalleryMode && viewMode !== 'grid5' && (
{creatorUsername || 'Anonym'}
)}
{/* Favorite Badge - Gallery Mode Only - Top Right */}
{isGalleryMode && isFavorite && (
)}
{/* Tags Preview - only in grid mode, hide in grid5 to save space */}
{viewMode !== 'grid5' && tags && tags.length > 0 && (
{tags.slice(0, viewMode === 'grid3' ? 1 : 2).map(tag => (
#{tag.name}
))}
{tags.length > (viewMode === 'grid3' ? 1 : 2) && (
+{tags.length - (viewMode === 'grid3' ? 1 : 2)}
)}
)}
);
// Wrap all cards with context menu (both gallery and explore mode)
return (
{CardContent}
);
}