Merge branch 'main' into home_page

This commit is contained in:
Sosokker 2025-05-08 21:40:21 +07:00
commit aec27ba56c
23 changed files with 965 additions and 109 deletions

View File

@ -1,29 +1,28 @@
import { Tabs } from 'expo-router'; import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import { Ionicons, MaterialCommunityIcons } from '@expo/vector-icons'; import { Tabs } from "expo-router";
import { View } from 'react-native';
export default function TabLayout() { export default function TabLayout() {
return ( return (
<Tabs <Tabs
screenOptions={{ screenOptions={{
tabBarStyle: { tabBarStyle: {
backgroundColor: '#ffd60a', backgroundColor: "#ffd60a",
height: 70, height: 70,
borderTopLeftRadius: 0, borderTopLeftRadius: 0,
borderTopRightRadius: 0, borderTopRightRadius: 0,
position: 'absolute', position: "absolute",
bottom: 0, bottom: 0,
left: 0, left: 0,
right: 0, right: 0,
elevation: 0, elevation: 0,
borderTopWidth: 0, borderTopWidth: 0,
}, },
tabBarActiveTintColor: '#bb0718', tabBarActiveTintColor: "#bb0718",
tabBarInactiveTintColor: '#bb0718', tabBarInactiveTintColor: "#bb0718",
tabBarShowLabel: true, tabBarShowLabel: true,
tabBarLabelStyle: { tabBarLabelStyle: {
fontSize: 12, fontSize: 12,
fontWeight: '500', fontWeight: "500",
}, },
headerShown: false, headerShown: false,
}} }}
@ -31,37 +30,46 @@ export default function TabLayout() {
<Tabs.Screen <Tabs.Screen
name="index" name="index"
options={{ options={{
title: 'Home', title: "Home",
tabBarIcon: ({ color }) => ( tabBarIcon: ({ color }) => (
<Ionicons name="home-outline" size={24} color={color} /> <Ionicons name="home-outline" size={24} color={color} />
), ),
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="recipes" name="recipes"
options={{ options={{
title: 'Recipes', title: "Recipes",
tabBarIcon: ({ color }) => ( tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="notebook-outline" size={24} color={color} /> <MaterialCommunityIcons
name="notebook-outline"
size={24}
color={color}
/>
), ),
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="forum" name="forum"
options={{ options={{
title: 'Forum', title: "Forum",
tabBarIcon: ({ color }) => ( tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="forum-outline" size={24} color={color} /> <MaterialCommunityIcons
name="forum-outline"
size={24}
color={color}
/>
), ),
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="profile"
name="profile" name="profile"
options={{ options={{
title: 'Profile', title: "Profile",
tabBarIcon: ({ color }) => ( tabBarIcon: ({ color }) => (
<Ionicons name="person-outline" size={24} color={color} /> <Ionicons name="person-outline" size={24} color={color} />
), ),
@ -69,4 +77,4 @@ export default function TabLayout() {
/> />
</Tabs> </Tabs>
); );
} }

View File

@ -1,10 +1,12 @@
import { View, Text } from 'react-native'; import { Text, View } from "react-native";
export default function ForumScreen() { export default function ForumScreen() {
return ( return (
<View className="flex-1 items-center justify-center bg-white"> <View className="flex-1 items-center justify-center bg-white">
<Text className="text-2xl font-bold">Forum Screen</Text> <Text className="text-2xl font-bold">Forum Screen</Text>
<Text className="mt-2 text-gray-500">Discussions and community posts will appear here</Text> <Text className="mt-2 text-gray-500">
Discussions and community posts will appear here
</Text>
</View> </View>
); );
} }

View File

@ -1,52 +1,65 @@
import React, { useState } from 'react'; import { Feather, FontAwesome, Ionicons } from "@expo/vector-icons";
import { View, Text, Image, TextInput, TouchableOpacity, SafeAreaView, StatusBar, ScrollView, Alert } from 'react-native'; import * as ImagePicker from "expo-image-picker";
import { Feather, FontAwesome, Ionicons } from '@expo/vector-icons'; import { router } from "expo-router";
import { router } from 'expo-router'; import React, { useState } from "react";
import * as ImagePicker from 'expo-image-picker'; import {
Alert,
Image,
SafeAreaView,
ScrollView,
StatusBar,
Text,
TextInput,
TouchableOpacity,
View,
} from "react-native";
// Sample recipe data // Sample recipe data
const recipeData = [ const recipeData = [
{ {
id: 1, id: 1,
title: "Pad Kra Pao Moo Sab with Eggs", title: "Pad Kra Pao Moo Sab with Eggs",
image: "/placeholder.svg?height=400&width=400&query=thai basil stir fry with egg and rice", image:
color: "#ffd60a" "/placeholder.svg?height=400&width=400&query=thai basil stir fry with egg and rice",
color: "#ffd60a",
}, },
{ {
id: 2, id: 2,
title: "Chicken Curry", title: "Chicken Curry",
image: "/placeholder.svg?height=400&width=400&query=chicken curry with rice", image:
color: "#ffd60a" "/placeholder.svg?height=400&width=400&query=chicken curry with rice",
color: "#ffd60a",
}, },
{ {
id: 3, id: 3,
title: "Beef Steak", title: "Beef Steak",
image: "/placeholder.svg?height=400&width=400&query=beef steak with vegetables", image:
color: "#bb0718" "/placeholder.svg?height=400&width=400&query=beef steak with vegetables",
color: "#bb0718",
}, },
{ {
id: 4, id: 4,
title: "Vegetable Pasta", title: "Vegetable Pasta",
image: "/placeholder.svg?height=400&width=400&query=vegetable pasta", image: "/placeholder.svg?height=400&width=400&query=vegetable pasta",
color: "#ffd60a" color: "#ffd60a",
}, },
{ {
id: 5, id: 5,
title: "Salmon Sushi", title: "Salmon Sushi",
image: "/placeholder.svg?height=400&width=400&query=salmon sushi", image: "/placeholder.svg?height=400&width=400&query=salmon sushi",
color: "#ffd60a" color: "#ffd60a",
} },
]; ];
export default function HomeScreen() { export default function HomeScreen() {
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState("");
const [filteredRecipes, setFilteredRecipes] = useState(recipeData); const [filteredRecipes, setFilteredRecipes] = useState(recipeData);
// Handle search // Handle search
const handleSearch = (text: string): void => { const handleSearch = (text: string): void => {
setSearchQuery(text); setSearchQuery(text);
if (text) { if (text) {
const filtered = recipeData.filter((recipe: Recipe) => const filtered = recipeData.filter((recipe: Recipe) =>
recipe.title.toLowerCase().includes(text.toLowerCase()) recipe.title.toLowerCase().includes(text.toLowerCase())
); );
setFilteredRecipes(filtered); setFilteredRecipes(filtered);
@ -54,63 +67,69 @@ export default function HomeScreen() {
setFilteredRecipes(recipeData); setFilteredRecipes(recipeData);
} }
}; };
// Handle camera // Handle camera
const takePhoto = async () => { const takePhoto = async () => {
const { status } = await ImagePicker.requestCameraPermissionsAsync(); const { status } = await ImagePicker.requestCameraPermissionsAsync();
if (status !== 'granted') { if (status !== "granted") {
Alert.alert('Permission needed', 'Please grant camera permissions to use this feature.'); Alert.alert(
"Permission needed",
"Please grant camera permissions to use this feature."
);
return; return;
} }
const result = await ImagePicker.launchCameraAsync({ const result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images, mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true, allowsEditing: true,
aspect: [1, 1], aspect: [1, 1],
quality: 1, quality: 1,
}); });
if (!result.canceled) { if (!result.canceled) {
// Navigate to recipe detail with the captured image // Navigate to recipe detail with the captured image
router.push({ router.push({
pathname: '/recipe-detail', pathname: "/recipe-detail",
params: { params: {
title: 'My New Recipe', title: "My New Recipe",
image: result.assets[0].uri image: result.assets[0].uri,
} },
}); });
} }
}; };
// Handle gallery // Handle gallery
const pickImage = async () => { const pickImage = async () => {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') { if (status !== "granted") {
Alert.alert('Permission needed', 'Please grant media library permissions to use this feature.'); Alert.alert(
"Permission needed",
"Please grant media library permissions to use this feature."
);
return; return;
} }
const result = await ImagePicker.launchImageLibraryAsync({ const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images, mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true, allowsEditing: true,
aspect: [1, 1], aspect: [1, 1],
quality: 1, quality: 1,
}); });
if (!result.canceled) { if (!result.canceled) {
// Navigate to recipe detail with the selected image // Navigate to recipe detail with the selected image
router.push({ router.push({
pathname: '/recipe-detail', pathname: "/recipe-detail",
params: { params: {
title: 'My New Recipe', title: "My New Recipe",
image: result.assets[0].uri image: result.assets[0].uri,
} },
}); });
} }
}; };
// Navigate to recipe detail // Navigate to recipe detail
interface Recipe { interface Recipe {
id: number; id: number;
@ -121,18 +140,18 @@ export default function HomeScreen() {
const goToRecipeDetail = (recipe: Recipe): void => { const goToRecipeDetail = (recipe: Recipe): void => {
router.push({ router.push({
pathname: '/recipe-detail', pathname: "/recipe-detail",
params: { params: {
title: recipe.title, title: recipe.title,
image: recipe.image image: recipe.image,
} },
}); });
}; };
return ( return (
<SafeAreaView className="flex-1 bg-white"> <SafeAreaView className="flex-1 bg-white">
<StatusBar barStyle="dark-content" /> <StatusBar barStyle="dark-content" />
{/* Header - Fixed at top */} {/* Header - Fixed at top */}
<View className="flex-row justify-between items-center px-6 pt-4 pb-2"> <View className="flex-row justify-between items-center px-6 pt-4 pb-2">
<Text className="text-3xl font-bold">Hi! Mr. Chef</Text> <Text className="text-3xl font-bold">Hi! Mr. Chef</Text>
@ -140,22 +159,22 @@ export default function HomeScreen() {
<Ionicons name="settings-outline" size={24} color="black" /> <Ionicons name="settings-outline" size={24} color="black" />
</View> </View>
</View> </View>
{/* Scrollable Content */} {/* Scrollable Content */}
<ScrollView <ScrollView
className="flex-1" className="flex-1"
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
contentContainerStyle={{ paddingBottom: 100 }} contentContainerStyle={{ paddingBottom: 100 }}
> >
{/* Show your dishes */} {/* Show your dishes */}
<View className="px-6 mb-6"> <View className="px-6 mb-6">
<View className="flex-row items-center mb-4"> <View className="flex-row items-center mb-4">
<Text className="text-2xl font-bold mr-2">Show your dishes</Text> <Text className="text-2xl font-bold mr-2">Show your dishes</Text>
<Feather name="wifi" size={20} color="black" /> <Feather name="wifi" size={20} color="black" />
</View> </View>
<View className="bg-white border border-gray-300 rounded-full mb-6 flex-row items-center px-4 py-3"> <View className="bg-white border border-gray-300 rounded-full mb-6 flex-row items-center px-4 py-3">
<TextInput <TextInput
className="flex-1" className="flex-1"
placeholder="Search..." placeholder="Search..."
value={searchQuery} value={searchQuery}
@ -165,48 +184,56 @@ export default function HomeScreen() {
<Feather name="send" size={20} color="black" /> <Feather name="send" size={20} color="black" />
</View> </View>
</View> </View>
<View className="flex-row justify-between"> <View className="flex-row justify-between">
<TouchableOpacity <TouchableOpacity
className="bg-[#ffd60a] p-4 rounded-xl w-[48%]" className="bg-[#ffd60a] p-4 rounded-xl w-[48%]"
onPress={takePhoto} onPress={takePhoto}
> >
<View className="items-center"> <View className="items-center">
<FontAwesome name="camera" size={24} color="black" /> <FontAwesome name="camera" size={24} color="black" />
<Text className="text-lg font-bold mt-2">From Camera</Text> <Text className="text-lg font-bold mt-2">From Camera</Text>
<Text className="text-sm text-gray-700">Straight from Camera</Text> <Text className="text-sm text-gray-700">
Straight from Camera
</Text>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity
className="bg-[#f9be25] p-4 rounded-xl w-[48%]" className="bg-[#f9be25] p-4 rounded-xl w-[48%]"
onPress={pickImage} onPress={pickImage}
> >
<View className="items-center"> <View className="items-center">
<Feather name="image" size={24} color="black" /> <Feather name="image" size={24} color="black" />
<Text className="text-lg font-bold mt-2">From Gallery</Text> <Text className="text-lg font-bold mt-2">From Gallery</Text>
<Text className="text-sm text-gray-700">Straight from Gallery</Text> <Text className="text-sm text-gray-700">
Straight from Gallery
</Text>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</View> </View>
{/* Highlights Section */} {/* Highlights Section */}
<View className="px-6 mb-6"> <View className="px-6 mb-6">
<View className="flex-row items-center mb-4"> <View className="flex-row items-center mb-4">
<Text className="text-2xl font-bold mr-2">Highlights</Text> <Text className="text-2xl font-bold mr-2">Highlights</Text>
<FontAwesome name="star" size={20} color="#ffd60a" /> <FontAwesome name="star" size={20} color="#ffd60a" />
</View> </View>
<ScrollView horizontal showsHorizontalScrollIndicator={false} className="mb-4"> <ScrollView
horizontal
showsHorizontalScrollIndicator={false}
className="mb-4"
>
<View className="flex-row"> <View className="flex-row">
{filteredRecipes.slice(0, 3).map((recipe) => ( {filteredRecipes.slice(0, 3).map((recipe) => (
<TouchableOpacity <TouchableOpacity
key={recipe.id} key={recipe.id}
className={`w-36 h-40 bg-[${recipe.color}] rounded-xl mr-3 overflow-hidden`} className={`w-36 h-40 bg-[${recipe.color}] rounded-xl mr-3 overflow-hidden`}
onPress={() => goToRecipeDetail(recipe)} onPress={() => goToRecipeDetail(recipe)}
> >
<Image <Image
source={{ uri: recipe.image }} source={{ uri: recipe.image }}
className="w-full h-full opacity-70" className="w-full h-full opacity-70"
/> />
@ -214,15 +241,15 @@ export default function HomeScreen() {
))} ))}
</View> </View>
</ScrollView> </ScrollView>
<View className="flex-row"> <View className="flex-row">
{filteredRecipes.slice(3, 5).map((recipe) => ( {filteredRecipes.slice(3, 5).map((recipe) => (
<TouchableOpacity <TouchableOpacity
key={recipe.id} key={recipe.id}
className={`w-36 h-40 bg-[${recipe.color}] rounded-xl mr-3 overflow-hidden`} className={`w-36 h-40 bg-[${recipe.color}] rounded-xl mr-3 overflow-hidden`}
onPress={() => goToRecipeDetail(recipe)} onPress={() => goToRecipeDetail(recipe)}
> >
<Image <Image
source={{ uri: recipe.image }} source={{ uri: recipe.image }}
className="w-full h-full opacity-70" className="w-full h-full opacity-70"
/> />
@ -230,10 +257,10 @@ export default function HomeScreen() {
))} ))}
</View> </View>
</View> </View>
{/* Extra space at bottom */} {/* Extra space at bottom */}
<View className="h-20"></View> <View className="h-20"></View>
</ScrollView> </ScrollView>
</SafeAreaView> </SafeAreaView>
); );
} }

View File

@ -1,10 +1,12 @@
import { View, Text } from 'react-native'; import { Text, View } from "react-native";
export default function ProfileScreen() { export default function ProfileScreen() {
return ( return (
<View className="flex-1 items-center justify-center bg-white"> <View className="flex-1 items-center justify-center bg-white">
<Text className="text-2xl font-bold">Profile Screen</Text> <Text className="text-2xl font-bold">Profile Screen</Text>
<Text className="mt-2 text-gray-500">Your profile information will appear here</Text> <Text className="mt-2 text-gray-500">
Your profile information will appear here
</Text>
</View> </View>
); );
} }

View File

@ -1,4 +1,4 @@
import { View, Text } from 'react-native'; import { Text, View } from "react-native";
export default function RecipesScreen() { export default function RecipesScreen() {
return ( return (
@ -7,4 +7,4 @@ export default function RecipesScreen() {
<Text className="mt-2 text-gray-500">Your recipes will appear here</Text> <Text className="mt-2 text-gray-500">Your recipes will appear here</Text>
</View> </View>
); );
} }

View File

@ -1,25 +1,25 @@
import { Stack } from 'expo-router'; import { Stack } from "expo-router";
import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { GestureHandlerRootView } from "react-native-gesture-handler";
import "../global.css" import "../global.css";
export default function RootLayout() { export default function RootLayout() {
return ( return (
<GestureHandlerRootView style={{ flex: 1 }}> <GestureHandlerRootView style={{ flex: 1 }}>
<Stack screenOptions={{ headerShown: false }}> <Stack screenOptions={{ headerShown: false }}>
<Stack.Screen <Stack.Screen
name="(tabs)" name="(tabs)"
options={{ options={{
headerShown: false
}}
/>
<Stack.Screen
name="recipe-detail"
options={{
headerShown: false, headerShown: false,
presentation: 'card' }}
}} />
<Stack.Screen
name="recipe-detail"
options={{
headerShown: false,
presentation: "card",
}}
/> />
</Stack> </Stack>
</GestureHandlerRootView> </GestureHandlerRootView>
); );
} }

363
app/cooking/[id].tsx Normal file
View File

@ -0,0 +1,363 @@
"use client";
import { IconSymbol } from "@/components/ui/IconSymbol";
import { Image } from "expo-image";
import { router, useLocalSearchParams } from "expo-router";
import { useState } from "react";
import {
Alert,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export default function CookingSessionScreen() {
const { id } = useLocalSearchParams();
const [currentStep, setCurrentStep] = useState(0);
// Mock data - in a real app, you would fetch this based on the ID
const recipeData = {
id: 1,
name: "Pad Kra Pao Moo Sab with Eggs",
steps: [
{
title: "Gather and prepare all ingredients",
description:
"Chop garlic, Thai chilies, and protein of choice (chicken, pork, beef, or tofu)",
image: require("@/assets/images/cooking/step1.png"),
},
{
title: "Heat oil in a wok or large frying pan",
description:
"Use medium-high heat. The oil should be hot but not smoking.",
image: require("@/assets/images/cooking/step2.png"),
},
{
title: "Fry the eggs sunny side up",
description:
"Heat oil in a separate pan and fry eggs until whites are set but yolks are still runny. Set aside.",
image: require("@/assets/images/cooking/step3.png"),
},
{
title: "Stir-fry garlic and chilies",
description:
"Add chopped garlic and chilies to the hot oil and stir-fry until fragrant, about 30 seconds.",
image: require("@/assets/images/cooking/step4.png"),
},
{
title: "Add ground pork and cook until browned",
description:
"Break up the meat with a spatula and cook until no longer pink, about 3-4 minutes.",
image: require("@/assets/images/cooking/step5.png"),
},
{
title: "Add sauces and basil",
description:
"Add soy sauce, oyster sauce, sugar, and holy basil. Stir well and cook for another minute. Serve with rice and top with the fried egg.",
image: require("@/assets/images/cooking/step6.png"),
},
],
};
const totalSteps = recipeData.steps.length;
const goToNextStep = () => {
if (currentStep < totalSteps - 1) {
setCurrentStep(currentStep + 1);
}
};
const goToPreviousStep = () => {
if (currentStep > 0) {
setCurrentStep(currentStep - 1);
}
};
const getHelpWithStep = () => {
Alert.alert(
"Need Help?",
`Tips for ${recipeData.steps[currentStep].title}:\n\n` +
"• Make sure ingredients are properly prepared\n" +
"• Watch your heat level\n" +
"• Don't overcook the ingredients\n\n" +
"Would you like to see a video tutorial?",
[
{ text: "No, thanks", style: "cancel" },
{
text: "Yes, show video",
onPress: () => console.log("Show video tutorial"),
},
]
);
};
const stopCookingSession = () => {
Alert.alert(
"Stop Cooking?",
"Are you sure you want to stop this cooking session?",
[
{ text: "Cancel", style: "cancel" },
{ text: "Yes, stop", onPress: () => router.back() },
]
);
};
return (
<SafeAreaView style={styles.container} edges={["top"]}>
<ScrollView style={styles.scrollView}>
{/* Header with back button */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => router.back()}
>
<IconSymbol name="chevron.left" size={24} color="#333333" />
</TouchableOpacity>
</View>
{/* Step Illustration */}
<View style={styles.illustrationContainer}>
<Image
source={recipeData.steps[currentStep].image}
style={styles.stepImage}
contentFit="contain"
/>
</View>
{/* Step Information */}
<View style={styles.stepInfoContainer}>
<Text style={styles.stepCounter}>
Step {currentStep + 1} of {totalSteps}
</Text>
<Text style={styles.stepTitle}>
{recipeData.steps[currentStep].title}
</Text>
<Text style={styles.stepDescription}>
{recipeData.steps[currentStep].description}
</Text>
</View>
{/* Step Indicators */}
<View style={styles.stepIndicatorsContainer}>
<Text style={styles.stepsLabel}>Steps</Text>
<View style={styles.stepDots}>
{recipeData.steps.map((_, index) => (
<TouchableOpacity
key={index}
onPress={() => setCurrentStep(index)}
>
<View
style={[
styles.stepDot,
currentStep === index && styles.activeStepDot,
]}
/>
</TouchableOpacity>
))}
</View>
</View>
{/* Navigation Buttons */}
<View style={styles.navigationContainer}>
<TouchableOpacity style={styles.helpButton} onPress={getHelpWithStep}>
<Text style={styles.helpButtonText}>Help me!</Text>
</TouchableOpacity>
<View style={styles.stepNavigation}>
{currentStep > 0 && (
<TouchableOpacity
style={[styles.navButton, styles.prevButton]}
onPress={goToPreviousStep}
>
<IconSymbol name="chevron.left" size={20} color="#333333" />
<Text style={styles.prevButtonText}>Previous</Text>
</TouchableOpacity>
)}
{currentStep < totalSteps - 1 ? (
<TouchableOpacity
style={[styles.navButton, styles.nextButton]}
onPress={goToNextStep}
>
<Text style={styles.nextButtonText}>Next Step</Text>
<IconSymbol name="chevron.right" size={20} color="#333333" />
</TouchableOpacity>
) : (
<TouchableOpacity
style={[styles.navButton, styles.finishButton]}
onPress={() => router.back()}
>
<Text style={styles.finishButtonText}>Finish</Text>
<IconSymbol name="checkmark" size={20} color="#FFFFFF" />
</TouchableOpacity>
)}
</View>
</View>
</ScrollView>
{/* Stop Session Button */}
<TouchableOpacity style={styles.stopButton} onPress={stopCookingSession}>
<Text style={styles.stopButtonText}>Stop Session</Text>
<IconSymbol name="fork.knife" size={20} color="#FFCC00" />
</TouchableOpacity>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#FFFFFF",
},
scrollView: {
flex: 1,
},
header: {
paddingHorizontal: 16,
paddingVertical: 12,
},
backButton: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "#FFCC00",
justifyContent: "center",
alignItems: "center",
},
illustrationContainer: {
alignItems: "center",
marginVertical: 20,
},
stepImage: {
width: 200,
height: 200,
borderRadius: 100,
backgroundColor: "#FFCC00",
},
stepInfoContainer: {
paddingHorizontal: 24,
alignItems: "center",
marginBottom: 30,
},
stepCounter: {
fontSize: 18,
color: "#8BC34A",
fontWeight: "bold",
marginBottom: 8,
},
stepTitle: {
fontSize: 24,
fontWeight: "bold",
color: "#333333",
textAlign: "center",
marginBottom: 12,
},
stepDescription: {
fontSize: 16,
color: "#666666",
textAlign: "center",
lineHeight: 24,
},
stepIndicatorsContainer: {
paddingHorizontal: 24,
marginBottom: 24,
},
stepsLabel: {
fontSize: 18,
fontWeight: "bold",
color: "#333333",
marginBottom: 12,
},
stepDots: {
flexDirection: "row",
justifyContent: "center",
},
stepDot: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "#EEEEEE",
marginHorizontal: 8,
},
activeStepDot: {
backgroundColor: "#FFCC00",
},
navigationContainer: {
paddingHorizontal: 24,
marginBottom: 80,
},
helpButton: {
backgroundColor: "#FF6B6B",
borderRadius: 8,
paddingVertical: 16,
alignItems: "center",
marginBottom: 16,
},
helpButtonText: {
fontSize: 18,
fontWeight: "bold",
color: "#FFFFFF",
},
stepNavigation: {
flexDirection: "row",
justifyContent: "space-between",
},
navButton: {
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
paddingVertical: 16,
borderRadius: 8,
},
prevButton: {
backgroundColor: "#FFFFFF",
borderWidth: 1,
borderColor: "#DDDDDD",
marginRight: 8,
},
prevButtonText: {
fontSize: 16,
fontWeight: "bold",
color: "#333333",
marginLeft: 8,
},
nextButton: {
backgroundColor: "#FFCC00",
},
nextButtonText: {
fontSize: 16,
fontWeight: "bold",
color: "#333333",
marginRight: 8,
},
finishButton: {
backgroundColor: "#4CAF50",
},
finishButtonText: {
fontSize: 16,
fontWeight: "bold",
color: "#FFFFFF",
marginRight: 8,
},
stopButton: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
backgroundColor: "#C62828",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
paddingVertical: 16,
},
stopButtonText: {
fontSize: 18,
fontWeight: "bold",
color: "#FFCC00",
marginRight: 8,
},
});

454
app/food/[id].tsx Normal file
View File

@ -0,0 +1,454 @@
"use client";
import { IconSymbol } from "@/components/ui/IconSymbol";
import { Image } from "expo-image";
import { router, useLocalSearchParams } from "expo-router";
import { useState } from "react";
import {
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export default function FoodDetailScreen() {
const { id } = useLocalSearchParams();
const [activeTab, setActiveTab] = useState("Ingredients");
// Mock data - in a real app, you would fetch this based on the ID
const foodData = {
id: 1,
name: "Pad Kra Pao Moo Sab with Eggs",
image: require("@/assets/images/food/padkrapao.jpg"),
description:
"Pad kra pao, also written as pad gaprao, is a popular Thai stir-fry of ground meat and holy basil.",
time: "30 Mins",
skills: "Easy",
ingredients: [
{ name: "Ground pork", emoji: "🥩" },
{ name: "Holy basil", emoji: "🌿" },
{ name: "Garlic", emoji: "🧄" },
{ name: "Thai chili", emoji: "🌶️" },
{ name: "Soy sauce", emoji: "🍶" },
{ name: "Oyster sauce", emoji: "🦪" },
{ name: "Sugar", emoji: "🧂" },
{ name: "Eggs", emoji: "🥚" },
],
calories: "520 kcal",
nutrition: {
fat: 15,
fiber: 3,
protein: 25,
carbs: 40,
},
steps: [
"Gather and prepare all ingredients",
"Heat oil in a wok or large frying pan",
"Fry the eggs sunny side up and set aside",
"Stir-fry garlic and chilies until fragrant",
"Add ground pork and cook until browned",
"Add sauces and basil, serve with rice and egg on top",
],
};
const startCookingSession = () => {
router.push(`/cooking/[id]`);
};
return (
<SafeAreaView style={styles.container} edges={["top"]}>
<ScrollView style={styles.scrollView}>
{/* Header with back and share buttons */}
<View style={styles.header}>
<TouchableOpacity
style={styles.backButton}
onPress={() => router.back()}
>
<IconSymbol name="chevron.left" size={24} color="#333333" />
</TouchableOpacity>
<TouchableOpacity style={styles.shareButton}>
<IconSymbol name="square.and.arrow.up" size={24} color="#FFCC00" />
</TouchableOpacity>
</View>
{/* Food Image */}
<View style={styles.imageContainer}>
<Image
source={foodData.image}
style={styles.foodImage}
contentFit="cover"
/>
</View>
{/* Food Title and Description */}
<View style={styles.contentContainer}>
<Text style={styles.foodTitle}>{foodData.name}</Text>
<Text style={styles.foodDescription}>{foodData.description}</Text>
{/* Info Tabs */}
<View style={styles.tabsContainer}>
<TouchableOpacity
style={styles.tabItem}
onPress={() => setActiveTab("Skills")}
>
<Text style={styles.tabLabel}>Skills</Text>
<Text style={styles.tabValue}>{foodData.skills}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.tabItem}
onPress={() => setActiveTab("Time")}
>
<Text style={styles.tabLabel}>Time</Text>
<Text style={styles.tabValue}>{foodData.time}</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.tabItem,
activeTab === "Ingredients" && styles.activeTabItem,
]}
onPress={() => setActiveTab("Ingredients")}
>
<Text style={styles.tabLabel}>Ingredients</Text>
<Text style={styles.tabValue}>{foodData.ingredients.length}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.tabItem}
onPress={() => setActiveTab("Calories")}
>
<Text style={styles.tabLabel}>Calories</Text>
<Text style={styles.tabValue}>{foodData.calories}</Text>
</TouchableOpacity>
</View>
{/* Ingredients Section */}
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>Ingredients</Text>
<View style={styles.ingredientsGrid}>
{foodData.ingredients.map((ingredient, index) => (
<View key={index} style={styles.ingredientItem}>
<View style={styles.ingredientIconContainer}>
<Text style={styles.ingredientEmoji}>
{ingredient.emoji}
</Text>
</View>
<Text style={styles.ingredientName}>{ingredient.name}</Text>
</View>
))}
</View>
</View>
{/* Nutrition Section - Improved UI */}
<View style={styles.nutritionSection}>
<Text style={styles.sectionTitle}>Nutrition Facts</Text>
<View style={styles.nutritionContainer}>
<View style={styles.nutritionItem}>
<View
style={[
styles.nutritionCircle,
{ backgroundColor: "#FFD700" },
]}
>
<Text style={styles.nutritionValue}>
{foodData.nutrition.fat}
</Text>
<Text style={styles.nutritionUnit}>g</Text>
</View>
<Text style={styles.nutritionLabel}>Fat</Text>
</View>
<View style={styles.nutritionItem}>
<View
style={[
styles.nutritionCircle,
{ backgroundColor: "#90EE90" },
]}
>
<Text style={styles.nutritionValue}>
{foodData.nutrition.fiber}
</Text>
<Text style={styles.nutritionUnit}>g</Text>
</View>
<Text style={styles.nutritionLabel}>Fiber</Text>
</View>
<View style={styles.nutritionItem}>
<View
style={[
styles.nutritionCircle,
{ backgroundColor: "#ADD8E6" },
]}
>
<Text style={styles.nutritionValue}>
{foodData.nutrition.protein}
</Text>
<Text style={styles.nutritionUnit}>g</Text>
</View>
<Text style={styles.nutritionLabel}>Protein</Text>
</View>
<View style={styles.nutritionItem}>
<View
style={[
styles.nutritionCircle,
{ backgroundColor: "#FFA07A" },
]}
>
<Text style={styles.nutritionValue}>
{foodData.nutrition.carbs}
</Text>
<Text style={styles.nutritionUnit}>g</Text>
</View>
<Text style={styles.nutritionLabel}>Carbs</Text>
</View>
</View>
</View>
{/* Steps Preview */}
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>Cooking Steps</Text>
<View style={styles.stepsPreviewContainer}>
{foodData.steps.slice(0, 2).map((step, index) => (
<View key={index} style={styles.stepPreviewItem}>
<View style={styles.stepNumberCircle}>
<Text style={styles.stepNumber}>{index + 1}</Text>
</View>
<Text style={styles.stepPreviewText}>{step}</Text>
</View>
))}
<Text style={styles.moreStepsText}>
...and {foodData.steps.length - 2} more steps
</Text>
</View>
</View>
</View>
</ScrollView>
{/* Cook Button */}
<TouchableOpacity style={styles.cookButton} onPress={startCookingSession}>
<Text style={styles.cookButtonText}>Let&apos;s Cook!</Text>
<IconSymbol name="fork.knife" size={20} color="#FFCC00" />
</TouchableOpacity>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#FFFFFF",
},
scrollView: {
flex: 1,
},
header: {
flexDirection: "row",
justifyContent: "space-between",
paddingHorizontal: 16,
paddingVertical: 12,
position: "absolute",
top: 0,
left: 0,
right: 0,
zIndex: 10,
},
backButton: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "#FFCC00",
justifyContent: "center",
alignItems: "center",
},
shareButton: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "#FFFFFF",
justifyContent: "center",
alignItems: "center",
},
imageContainer: {
alignItems: "center",
marginTop: 60,
marginBottom: 20,
},
foodImage: {
width: 200,
height: 200,
borderRadius: 100,
borderWidth: 5,
borderColor: "#FFFFFF",
},
contentContainer: {
paddingHorizontal: 16,
},
foodTitle: {
fontSize: 24,
fontWeight: "bold",
color: "#333333",
marginBottom: 8,
},
foodDescription: {
fontSize: 16,
color: "#666666",
marginBottom: 20,
lineHeight: 22,
},
tabsContainer: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 20,
},
tabItem: {
alignItems: "center",
},
activeTabItem: {
borderBottomWidth: 2,
borderBottomColor: "#333333",
},
tabLabel: {
fontSize: 14,
color: "#666666",
},
tabValue: {
fontSize: 16,
fontWeight: "bold",
color: "#333333",
marginTop: 4,
},
sectionContainer: {
marginBottom: 20,
},
sectionTitle: {
fontSize: 20,
fontWeight: "bold",
color: "#333333",
marginBottom: 16,
},
ingredientsGrid: {
flexDirection: "row",
flexWrap: "wrap",
},
ingredientItem: {
width: "25%",
alignItems: "center",
marginBottom: 16,
},
ingredientIconContainer: {
width: 60,
height: 60,
borderRadius: 30,
backgroundColor: "#F8F8F8",
justifyContent: "center",
alignItems: "center",
marginBottom: 8,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 2,
},
ingredientEmoji: {
fontSize: 30,
},
ingredientName: {
fontSize: 12,
textAlign: "center",
color: "#333333",
},
nutritionSection: {
marginBottom: 20,
},
nutritionContainer: {
flexDirection: "row",
justifyContent: "space-between",
backgroundColor: "#FFFFFF",
borderRadius: 12,
padding: 16,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 2,
},
nutritionItem: {
alignItems: "center",
},
nutritionCircle: {
width: 60,
height: 60,
borderRadius: 30,
justifyContent: "center",
alignItems: "center",
marginBottom: 8,
},
nutritionValue: {
fontSize: 18,
fontWeight: "bold",
color: "#333333",
},
nutritionUnit: {
fontSize: 12,
color: "#333333",
position: "absolute",
bottom: 10,
right: 10,
},
nutritionLabel: {
fontSize: 14,
fontWeight: "500",
color: "#333333",
},
stepsPreviewContainer: {
backgroundColor: "#F8F8F8",
borderRadius: 12,
padding: 16,
},
stepPreviewItem: {
flexDirection: "row",
alignItems: "center",
marginBottom: 12,
},
stepNumberCircle: {
width: 30,
height: 30,
borderRadius: 15,
backgroundColor: "#FFCC00",
justifyContent: "center",
alignItems: "center",
marginRight: 12,
},
stepNumber: {
fontSize: 16,
fontWeight: "bold",
color: "#333333",
},
stepPreviewText: {
fontSize: 16,
color: "#333333",
flex: 1,
},
moreStepsText: {
fontSize: 14,
color: "#666666",
fontStyle: "italic",
textAlign: "center",
marginTop: 8,
},
cookButton: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
backgroundColor: "#FF0000",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
paddingVertical: 16,
},
cookButtonText: {
fontSize: 18,
fontWeight: "bold",
color: "#FFCC00",
marginRight: 8,
},
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

BIN
assets/images/food/beef.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB