import React, { useMemo, useState, useRef, useEffect } from 'react'; import { ActivityIndicator, Alert, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View, Dimensions, } from 'react-native'; import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; import { useRouter } from 'expo-router'; import { Ionicons } from '@expo/vector-icons'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useApp } from '../../context/AppContext'; import { useColors } from '../../constants/Colors'; import { ThemeBackdrop } from '../../components/ThemeBackdrop'; import { SafeImage } from '../../components/SafeImage'; import { Plant } from '../../types'; import { useCoachMarks } from '../../context/CoachMarksContext'; const { width: SCREEN_W, height: SCREEN_H } = Dimensions.get('window'); type FilterKey = 'all' | 'today' | 'week' | 'healthy' | 'dormant'; const DAY_MS = 24 * 60 * 60 * 1000; const CONTENT_BOTTOM_PADDING = 12; const FAB_BOTTOM_OFFSET = 16; function OnboardingChecklist({ plantsCount, colors, router, t }: { plantsCount: number; colors: any; router: any; t: any }) { const checklist = [ { id: 'scan', label: t.stepScan, completed: plantsCount > 0, icon: 'camera-outline', route: '/scanner' }, { id: 'lexicon', label: t.stepLexicon, completed: false, icon: 'search-outline', route: '/lexicon' }, { id: 'theme', label: t.stepTheme, completed: false, icon: 'color-palette-outline', route: '/profile/preferences' }, ]; return ( {t.nextStepsTitle} {checklist.map((item) => ( { if (item.id === 'theme') { router.push('/profile/preferences'); } else if (item.id === 'scan') { router.push('/scanner'); } else if (item.id === 'lexicon') { router.push('/lexicon'); } else { router.push(item.route); } }} disabled={item.completed} > {item.label} {!item.completed && } ))} ); } const getDaysUntilWatering = (plant: Plant): number => { const lastWateredTs = new Date(plant.lastWatered).getTime(); if (Number.isNaN(lastWateredTs)) return 0; const dueTs = lastWateredTs + (plant.careInfo.waterIntervalDays * DAY_MS); const remainingMs = dueTs - Date.now(); if (remainingMs <= 0) return 0; return Math.ceil(remainingMs / DAY_MS); }; export default function HomeScreen() { const { plants, isLoadingPlants, profileImageUri, profileName, billingSummary, isLoadingBilling, language, t, isDarkMode, colorPalette, } = useApp(); const colors = useColors(isDarkMode, colorPalette); const router = useRouter(); const insets = useSafeAreaInsets(); const [activeFilter, setActiveFilter] = useState('all'); const { registerLayout, startTour } = useCoachMarks(); const fabRef = useRef(null); // Tour nach Registrierung starten useEffect(() => { const checkTour = async () => { const flag = await AsyncStorage.getItem('greenlens_show_tour'); if (flag !== 'true') return; await AsyncStorage.removeItem('greenlens_show_tour'); // 1 Sekunde warten, dann Tour starten setTimeout(() => { // Tab-Positionen approximieren (gleichmäßig verteilt) const tabBarBottom = SCREEN_H - 85; const tabW = SCREEN_W / 3; registerLayout('tab_search', { x: tabW, y: tabBarBottom + 8, width: tabW, height: 52 }); registerLayout('tab_profile', { x: tabW * 2, y: tabBarBottom + 8, width: tabW, height: 52 }); startTour([ { elementKey: 'fab', title: t.tourFabTitle, description: t.tourFabDesc, tooltipSide: 'above', }, { elementKey: 'tab_search', title: t.tourSearchTitle, description: t.tourSearchDesc, tooltipSide: 'above', }, { elementKey: 'tab_profile', title: t.tourProfileTitle, description: t.tourProfileDesc, tooltipSide: 'above', }, ]); }, 1000); }; checkTour(); }, []); const copy = t; const greetingText = useMemo(() => { const hour = new Date().getHours(); if (hour < 12) return copy.greetingMorning; if (hour < 18) return copy.greetingAfternoon; return copy.greetingEvening; }, [copy.greetingAfternoon, copy.greetingEvening, copy.greetingMorning]); const creditsText = useMemo(() => { if (isLoadingBilling && !billingSummary) { return '...'; } if (!billingSummary) { return `-- ${copy.creditsLabel}`; } return `${billingSummary.credits.available} ${copy.creditsLabel}`; }, [billingSummary, copy.creditsLabel, isLoadingBilling]); const thirstyCount = useMemo( () => plants.filter(plant => getDaysUntilWatering(plant) === 0).length, [plants] ); const dueTodayPlants = useMemo( () => plants.filter(plant => getDaysUntilWatering(plant) === 0), [plants] ); const filteredPlants = useMemo(() => { return plants.filter((plant) => { if (activeFilter === 'all') return true; const daysUntil = getDaysUntilWatering(plant); if (activeFilter === 'today') return daysUntil === 0; if (activeFilter === 'week') return daysUntil <= 7; if (activeFilter === 'healthy') return daysUntil >= 2; return plant.careInfo.waterIntervalDays >= 14; }); }, [plants, activeFilter]); const chips: Array<{ key: FilterKey; label: string }> = [ { key: 'all', label: copy.all }, { key: 'today', label: copy.today }, { key: 'week', label: copy.week }, { key: 'healthy', label: copy.healthy }, { key: 'dormant', label: copy.dormant }, ]; const handleBellPress = () => { setActiveFilter('today'); if (dueTodayPlants.length === 0) { Alert.alert(copy.reminderTitle, copy.reminderNone); return; } const previewNames = dueTodayPlants .slice(0, 6) .map((plant) => `- ${plant.name}`) .join('\n'); const remainingCount = dueTodayPlants.length - 6; const remainingText = remainingCount > 0 ? `\n+ ${remainingCount} ${copy.more}` : ''; Alert.alert( copy.reminderTitle, `${copy.reminderDue.replace('{0}', dueTodayPlants.length.toString())}\n\n${previewNames}${remainingText}` ); }; if (isLoadingPlants) { return ( ); } return ( {profileImageUri ? ( ) : ( )} {greetingText} {profileName || ''} {creditsText} {copy.needsWaterToday} {copy.plantsThirsty.replace('{0}', thirstyCount.toString())} {copy.viewSchedule} {plants.length === 0 && ( )} {chips.map(chip => ( setActiveFilter(chip.key)} activeOpacity={0.85} > {chip.label} ))} {copy.collectionTitle} {copy.collectionCount.replace('{0}', filteredPlants.length.toString())} {filteredPlants.length === 0 ? ( {plants.length === 0 ? copy.emptyCollectionTitle : copy.noneInFilter} {plants.length === 0 ? copy.emptyCollectionHint : copy.noneInFilter} {plants.length === 0 && ( router.push('/scanner')} activeOpacity={0.86} > {copy.scanFirstPlant} )} ) : ( filteredPlants.map((plant) => { const daysUntil = getDaysUntilWatering(plant); const thirsty = daysUntil === 0; const nextWaterText = thirsty ? copy.today : t.inXDays.replace('{0}', daysUntil.toString()); return ( router.push(`/plant/${plant.id}`)} > {plant.name} {plant.botanicalName} {thirsty ? copy.thirsty : copy.healthyStatus} {copy.nextWaterLabel}: {nextWaterText} ); }) )} router.push('/scanner')} onLayout={() => { fabRef.current?.measureInWindow((x, y, width, height) => { registerLayout('fab', { x, y, width, height }); }); }} > ); } const styles = StyleSheet.create({ container: { flex: 1, }, loadingContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', }, content: { paddingHorizontal: 24, paddingTop: 14, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 26, }, headerLeft: { flexDirection: 'row', alignItems: 'center', gap: 12, flex: 1, }, headerTextBlock: { flex: 1, minWidth: 0, }, avatarWrap: { width: 48, height: 48, borderRadius: 16, alignItems: 'center', justifyContent: 'center', overflow: 'hidden', }, avatarImage: { width: '100%', height: '100%', }, greetingText: { fontSize: 13, fontWeight: '600', }, nameRow: { marginTop: 1, flexDirection: 'row', alignItems: 'center', gap: 8, minWidth: 0, }, nameText: { fontSize: 21, fontWeight: '700', letterSpacing: 0.1, flexShrink: 1, }, creditsPill: { borderRadius: 999, borderWidth: 1, paddingHorizontal: 8, paddingVertical: 3, }, creditsText: { fontSize: 10, fontWeight: '700', letterSpacing: 0.3, textTransform: 'uppercase', }, bellBtn: { width: 46, height: 46, borderRadius: 16, borderWidth: 1, alignItems: 'center', justifyContent: 'center', shadowOpacity: 0.08, shadowRadius: 8, shadowOffset: { width: 0, height: 2 }, elevation: 2, }, priorityCard: { borderRadius: 32, padding: 24, marginBottom: 20, overflow: 'hidden', }, priorityLabelRow: { flexDirection: 'row', alignItems: 'center', gap: 6, marginBottom: 8, }, priorityLabel: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.9, }, priorityTitle: { fontSize: 29, fontWeight: '700', lineHeight: 36, maxWidth: 260, marginBottom: 14, }, priorityButton: { alignSelf: 'flex-start', borderRadius: 16, borderWidth: 1, paddingHorizontal: 16, paddingVertical: 10, flexDirection: 'row', alignItems: 'center', gap: 6, }, priorityButtonText: { fontSize: 13, fontWeight: '700', }, priorityBgIcon: { position: 'absolute', right: -18, bottom: -22, }, filterRow: { gap: 10, paddingVertical: 2, paddingRight: 4, marginBottom: 16, }, collectionHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, }, collectionTitle: { fontSize: 19, fontWeight: '700', letterSpacing: 0.2, }, collectionCountPill: { borderRadius: 999, borderWidth: 1, paddingHorizontal: 10, paddingVertical: 4, }, collectionCountText: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.4, }, filterChip: { paddingHorizontal: 22, paddingVertical: 10, borderRadius: 16, borderWidth: 1, }, filterChipActive: { paddingHorizontal: 22, paddingVertical: 10, borderRadius: 16, shadowOpacity: 0.24, shadowRadius: 10, shadowOffset: { width: 0, height: 3 }, elevation: 3, }, filterText: { fontSize: 13, fontWeight: '700', }, filterTextActive: { fontSize: 13, fontWeight: '700', }, plantCard: { borderRadius: 30, borderWidth: 1, padding: 15, flexDirection: 'row', alignItems: 'flex-start', gap: 14, marginBottom: 14, shadowOpacity: 0.1, shadowRadius: 12, shadowOffset: { width: 0, height: 4 }, elevation: 3, }, plantImageWrap: { borderWidth: 1, borderRadius: 20, overflow: 'hidden', }, plantImage: { width: 98, height: 98, borderRadius: 20, }, plantBody: { flex: 1, paddingTop: 2, }, plantHeadRow: { flexDirection: 'row', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 8, gap: 8, }, plantTitleCol: { flex: 1, minWidth: 0, }, plantName: { fontWeight: '700', fontSize: 19, letterSpacing: 0.15, }, botanicalName: { fontSize: 12.5, fontStyle: 'italic', fontWeight: '500', marginTop: 2, opacity: 0.95, }, metaRow: { flexDirection: 'row', alignItems: 'center', gap: 8, flexWrap: 'wrap', }, statusThirsty: { borderRadius: 20, paddingHorizontal: 10, paddingVertical: 4, }, statusHealthy: { borderRadius: 20, paddingHorizontal: 10, paddingVertical: 4, }, statusThirstyText: { fontSize: 10, fontWeight: '800', textTransform: 'uppercase', letterSpacing: 0.4, }, statusHealthyText: { fontSize: 10, fontWeight: '800', textTransform: 'uppercase', letterSpacing: 0.4, }, waterMeta: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.4, }, nextWaterPill: { borderRadius: 999, borderWidth: 1, paddingHorizontal: 9, paddingVertical: 4, flexDirection: 'row', alignItems: 'center', gap: 4, }, emptyState: { borderRadius: 24, borderWidth: 1, paddingVertical: 32, paddingHorizontal: 22, alignItems: 'center', gap: 10, }, emptyIconWrap: { width: 56, height: 56, borderRadius: 18, alignItems: 'center', justifyContent: 'center', }, emptyTitle: { fontSize: 18, fontWeight: '700', textAlign: 'center', }, emptyText: { fontSize: 13, fontWeight: '500', textAlign: 'center', lineHeight: 20, }, emptyCta: { marginTop: 8, borderRadius: 999, paddingHorizontal: 16, paddingVertical: 10, flexDirection: 'row', alignItems: 'center', gap: 8, shadowOpacity: 0.3, shadowRadius: 10, shadowOffset: { width: 0, height: 4 }, elevation: 4, }, emptyCtaText: { fontSize: 13, fontWeight: '700', }, fab: { position: 'absolute', right: 24, width: 66, height: 66, borderRadius: 33, borderWidth: 4, alignItems: 'center', justifyContent: 'center', shadowOpacity: 0.38, shadowRadius: 14, shadowOffset: { width: 0, height: 5 }, elevation: 9, }, checklistCard: { borderRadius: 24, borderWidth: 1, padding: 20, marginBottom: 20, }, checklistTitle: { fontSize: 16, fontWeight: '700', marginBottom: 16, }, checklistGrid: { gap: 12, }, checklistItem: { flexDirection: 'row', alignItems: 'center', gap: 12, }, checkIcon: { width: 32, height: 32, borderRadius: 16, justifyContent: 'center', alignItems: 'center', }, checklistText: { flex: 1, fontSize: 14, fontWeight: '500', }, });