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',
},
});