0% found this document useful (0 votes)
5 views28 pages

Code

The document contains code for a React Native application that includes a root layout with theming, a not found screen, and a home screen for a hairstyle transformation app. It allows users to upload images, select hairstyle options, and apply transformations using AI, while managing user authentication with Firebase. The code also includes styling for various components and handles image uploads and downloads.

Uploaded by

Kristine Egido
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views28 pages

Code

The document contains code for a React Native application that includes a root layout with theming, a not found screen, and a home screen for a hairstyle transformation app. It allows users to upload images, select hairstyle options, and apply transformations using AI, while managing user authentication with Firebase. The code also includes styling for various components and handles image uploads and downloads.

Uploaded by

Kristine Egido
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Layout CODE

import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';

import { useFonts } from 'expo-font';

import { Stack } from 'expo-router';

import { StatusBar } from 'expo-status-bar';

import 'react-native-reanimated';

import { useColorScheme } from '@/hooks/useColorScheme';

export default function RootLayout() {

const colorScheme = useColorScheme();

const [loaded] = useFonts({

SpaceMono: require('../assets/fonts/[Link]'),

});

if (!loaded) {

// Async font loading only occurs in development.

return null;

return (

<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>

<Stack initialRouteName="index">

<[Link] name="index" options={{ headerShown: false }} />

<[Link] name="(tabs)" options={{ headerShown: false }} />

<[Link] name="+not-found" />

</Stack>

<StatusBar style="auto" />

</ThemeProvider>

);

}
Not Found CODE

Import { Link, Stack } from 'expo-router';

import { StyleSheet } from 'react-native';

import { ThemedText } from '@/components/ThemedText';

import { ThemedView } from '@/components/ThemedView';

export default function NotFoundScreen() {

return (

<>

<[Link] options={{ title: 'Oops!' }} />

<ThemedView style={[Link]}>

<ThemedText type="title">This screen does not exist.</ThemedText>

<Link href="/" style={[Link]}>

<ThemedText type="link">Go to home screen!</ThemedText>

</Link>

</ThemedView>

</>

);

const styles = [Link]({

container: {

flex: 1,

alignItems: 'center',

justifyContent: 'center',

padding: 20,

},

link: {
marginTop: 15,

paddingVertical: 15,

},

});
Home CODE

import * as ImagePicker from "expo-image-picker";

import { useRouter } from "expo-router";

import { signOut } from "firebase/auth";

import { useState } from "react";

import { ActivityIndicator, Alert, Image, Linking, Pressable, ScrollView, StyleSheet, Text, TextInput,
View } from "react-native";

import { uploadToCloudinary } from "../components/cloudinary";

import { getGenerativeRemoveUrl, getGenerativeReplaceUrl } from


"../components/cloudinaryGen";

import { auth } from "../firebaseConfig";

export default function Home() {

const [fromPrompt, setFromPrompt] = useState("hair");

const [toPrompt, setToPrompt] = useState("curly hair with bangs");

const router = useRouter();

const [image, setImage] = useState<string | null>(null);

const [generativeUrl, setGenerativeUrl] = useState<string | null>(null);

const [removeUrl, setRemoveUrl] = useState<string | null>(null);

const [publicId, setPublicId] = useState<string | null>(null);

const [uploading, setUploading] = useState(false);

// Predefined hairstyle options

const hairstyleOptions = [

{ label: "Long Hair", value: "long hair", emoji: "💁‍♀️" },

{ label: "Short Hair", value: "short hair", emoji: "👩‍🦱" },

{ label: "Curly Hair", value: "curly hair with bangs", emoji: "🌀" },

{ label: "Straight Hair", value: "straight long hair", emoji: "💇‍♀️" },

{ label: "Bob Cut", value: "bob haircut", emoji: "👩‍💼" },


{ label: "Pixie Cut", value: "pixie cut short hair", emoji: "🧚‍♀️" },

{ label: "Afro Hair", value: "afro hairstyle", emoji: "👩‍🦲" },

{ label: "Braided Hair", value: "braided hairstyle", emoji: "👸" },

{ label: "Wavy Hair", value: "wavy hair", emoji: "🌊" },

{ label: "Ponytail", value: "high ponytail", emoji: "🐴" },

{ label: "Bangs", value: "hair with bangs", emoji: "💫" },

{ label: "Bald", value: "bald head", emoji: "👨‍🦲" },

];

const handleGenerativeRemove = () => {

if (publicId) {

const url = getGenerativeRemoveUrl(publicId, fromPrompt);

setRemoveUrl(url);

};

const downloadImage = async (imageUri: string, imageName: string) => {

try {

// Open the image URL in the browser for download

const supported = await [Link](imageUri);

if (supported) {

await [Link](imageUri);

[Link]('Download', `Opening ${imageName} in browser for download.`);

} else {

[Link]('Error', 'Cannot open image URL.');

} catch (error) {

[Link]('Error opening image:', error);

[Link]('Error', 'Failed to open image for download.');


}

};

const logout = async () => {

await signOut(auth);

[Link]("/");

};

const pickImage = async () => {

const permission = await [Link]();

if (![Link]) {

alert("Permission required to access photos!");

return;

const result = await [Link]({

mediaTypes: [Link],

allowsEditing: true,

aspect: [4, 4],

quality: 1,

});

if (![Link]) {

const uri = [Link][0].uri;

await uploadImage(uri);

};

const uploadImage = async (uri: string) => {


try {

setUploading(true);

setGenerativeUrl(null);

setRemoveUrl(null);

// Upload to Cloudinary

const uploadRes = await uploadToCloudinary(uri);

setImage(uploadRes.secure_url);

// Save publicId for later use

const publicId = uploadRes.public_id;

setPublicId(publicId);

// Apply generative replace effect with user prompts

const genUrl = getGenerativeReplaceUrl(publicId, fromPrompt, toPrompt);

setGenerativeUrl(genUrl);

} catch (error: any) {

[Link](error);

alert("Upload failed: " + ([Link] || error));

} finally {

setUploading(false);

};

return (

<ScrollView style={[Link]} contentContainerStyle={[Link]}>

{/* Header */}

<View style={[Link]}>

<View style={[Link]}>

<Text style={[Link]}>HairStyle App</Text>

<Text style={[Link]}>Transform your hairstyle with Us</Text>

</View>
<Pressable style={[Link]} onPress={logout}>

<Text style={[Link]}>Logout</Text>

</Pressable>

</View>

{/* Welcome Section */}

<View style={[Link]}>

<Text style={[Link]}>Welcome back!</Text>

<Text style={[Link]}>{[Link]?.email}</Text>

</View>

{/* Input Section */}

<View style={[Link]}>

<Text style={[Link]}>Transformation Settings</Text>

<View style={[Link]}>

<Text style={[Link]}>What to replace:</Text>

<TextInput

value={fromPrompt}

onChangeText={setFromPrompt}

placeholder="e.g. hairstyle, hat, shirt"

placeholderTextColor="#94a3b8"

style={[Link]}

/>

</View>

<View style={[Link]}>

<Text style={[Link]}>Choose Hairstyle:</Text>

<View style={[Link]}>
{[Link]((option) => (

<Pressable

key={[Link]}

style={[

[Link],

toPrompt === [Link] && [Link]

]}

onPress={() => setToPrompt([Link])}

>

<Text style={[Link]}>{[Link]}</Text>

<Text style={[

[Link],

toPrompt === [Link] && [Link]

]}>{[Link]}</Text>

</Pressable>

))}

</View>

</View>

</View>

{/* Upload Section */}

<View style={[Link]}>

<Pressable style={[Link]} onPress={pickImage} disabled={uploading}>

<Text style={[Link]}>

{uploading ? "Processing..." : "📸 Pick & Transform Photo"}

</Text>

</Pressable>

{uploading && (
<View style={[Link]}>

<ActivityIndicator size="large" color="#3b82f6" />

<Text style={[Link]}>Applying AI magic...</Text>

</View>

)}

</View>

{/* Results Section */}

{(image || generativeUrl || removeUrl) && (

<View style={[Link]}>

<Text style={[Link]}>Results</Text>

<View style={[Link]}>

{/* Original Image */}

{image && (

<View style={[Link]}>

<Text style={[Link]}>Original</Text>

<Image source={{ uri: image }} style={[Link]} />

</View>

)}

{/* Generative Replace Image */}

{generativeUrl && (

<View style={[Link]}>

<Text style={[Link]}>AI Transform</Text>

<Image source={{ uri: generativeUrl }} style={[Link]} />

<Pressable

style={[Link]}

onPress={() => downloadImage(generativeUrl, 'AI Transform')}


>

<Text style={[Link]}>💾 Download</Text>

</Pressable>

</View>

)}

{/* Generative Remove Image */}

{removeUrl && (

<View style={[Link]}>

<Text style={[Link]}>AI Remove</Text>

<Image source={{ uri: removeUrl }} style={[Link]} />

<Pressable

style={[Link]}

onPress={() => downloadImage(removeUrl, 'AI Remove')}

>

<Text style={[Link]}>💾 Download</Text>

</Pressable>

</View>

)}

</View>

</View>

)}

</ScrollView>

);

const styles = [Link]({

container: {

flex: 1,
backgroundColor: '#0f172a', // Dark slate background

},

contentContainer: {

paddingBottom: 30,

},

header: {

flexDirection: 'row',

justifyContent: 'space-between',

alignItems: 'flex-start',

paddingHorizontal: 20,

paddingTop: 60,

paddingBottom: 20,

backgroundColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',

},

headerContent: {

flex: 1,

},

appTitle: {

fontSize: 32,

fontWeight: 'bold',

color: '#ffffff',

marginBottom: 4,

},

subtitle: {

fontSize: 16,

color: '#e2e8f0',

opacity: 0.9,

},

logoutButton: {
backgroundColor: 'rgba(255, 255, 255, 0.2)',

paddingHorizontal: 16,

paddingVertical: 8,

borderRadius: 20,

borderWidth: 1,

borderColor: 'rgba(255, 255, 255, 0.3)',

},

logoutText: {

color: '#ffffff',

fontSize: 14,

fontWeight: '600',

},

welcomeCard: {

backgroundColor: '#1e293b',

marginHorizontal: 20,

marginTop: -10,

marginBottom: 20,

padding: 20,

borderRadius: 16,

shadowColor: '#000',

shadowOffset: { width: 0, height: 4 },

shadowOpacity: 0.3,

shadowRadius: 8,

elevation: 8,

},

welcomeText: {

fontSize: 20,

fontWeight: '600',

color: '#f1f5f9',
marginBottom: 4,

},

userEmail: {

fontSize: 14,

color: '#94a3b8',

},

inputSection: {

marginHorizontal: 20,

marginBottom: 24,

},

sectionTitle: {

fontSize: 18,

fontWeight: '600',

color: '#f1f5f9',

marginBottom: 16,

},

inputContainer: {

marginBottom: 16,

},

inputLabel: {

fontSize: 14,

fontWeight: '500',

color: '#cbd5e1',

marginBottom: 8,

},

textInput: {

backgroundColor: '#334155',

borderWidth: 1,

borderColor: '#475569',
borderRadius: 12,

padding: 16,

fontSize: 16,

color: '#f1f5f9',

minHeight: 50,

},

uploadSection: {

marginHorizontal: 20,

marginBottom: 24,

},

uploadButton: {

backgroundColor: '#3b82f6',

padding: 18,

borderRadius: 16,

alignItems: 'center',

shadowColor: '#3b82f6',

shadowOffset: { width: 0, height: 4 },

shadowOpacity: 0.3,

shadowRadius: 8,

elevation: 8,

},

uploadButtonText: {

color: '#ffffff',

fontSize: 18,

fontWeight: '600',

},

loadingContainer: {

alignItems: 'center',

marginTop: 20,
},

loadingText: {

color: '#94a3b8',

fontSize: 16,

marginTop: 12,

},

resultsSection: {

marginHorizontal: 20,

},

imageGrid: {

gap: 16,

},

imageCard: {

backgroundColor: '#1e293b',

borderRadius: 16,

padding: 16,

alignItems: 'center',

shadowColor: '#000',

shadowOffset: { width: 0, height: 2 },

shadowOpacity: 0.25,

shadowRadius: 6,

elevation: 6,

marginBottom: 16,

},

imageTitle: {

fontSize: 16,

fontWeight: '600',

color: '#f1f5f9',

marginBottom: 12,
},

resultImage: {

width: 280,

height: 280,

borderRadius: 12,

marginBottom: 16,

},

downloadButton: {

backgroundColor: '#10b981',

paddingHorizontal: 24,

paddingVertical: 12,

borderRadius: 12,

minWidth: 140,

alignItems: 'center',

},

downloadButtonText: {

color: '#ffffff',

fontSize: 16,

fontWeight: '600',

},

hairstyleGrid: {

flexDirection: 'row',

flexWrap: 'wrap',

gap: 12,

marginTop: 8,

},

hairstyleCard: {

backgroundColor: '#1e293b',

borderRadius: 12,
padding: 12,

alignItems: 'center',

justifyContent: 'center',

minWidth: 85,

minHeight: 85,

shadowColor: '#000',

shadowOffset: { width: 0, height: 2 },

shadowOpacity: 0.1,

shadowRadius: 4,

elevation: 3,

borderWidth: 2,

borderColor: 'transparent',

},

selectedCard: {

backgroundColor: '#3b82f6',

borderColor: '#60a5fa',

shadowColor: '#3b82f6',

shadowOpacity: 0.3,

},

emoji: {

fontSize: 24,

marginBottom: 4,

},

cardLabel: {

fontSize: 11,

fontWeight: '500',

color: '#94a3b8',

textAlign: 'center',

lineHeight: 14,
},

selectedCardLabel: {

color: '#ffffff',

fontWeight: '600',

},

});

INDEX CODE
import React, { useState } from "react";

import { View, TextInput, Text, StyleSheet, TouchableOpacity } from "react-native";

import { signInWithEmailAndPassword } from "firebase/auth";

import { auth } from "../firebaseConfig";

import { useRouter } from "expo-router";

export default function Login() {

const [email, setEmail] = useState("");

const [password, setPassword] = useState("");

const router = useRouter();

const handleLogin = async () => {

try {

await signInWithEmailAndPassword(auth, email, password);

[Link]("/home"); // 👈 go to home screen

} catch (error: any) {

alert([Link]);

};

return (

<View style={[Link]}>

<Text style={[Link]}>Login</Text>

<TextInput

style={[Link]}

placeholder="Email"

placeholderTextColor="#666"

value={email}

onChangeText={setEmail}
/>

<TextInput

style={[Link]}

placeholder="Password"

placeholderTextColor="#666"

secureTextEntry

value={password}

onChangeText={setPassword}

/>

<TouchableOpacity style={[Link]} onPress={handleLogin} activeOpacity={0.8}>

<Text style={[Link]}>Login</Text>

</TouchableOpacity>

<TouchableOpacity style={[Link]} onPress={() => [Link]("/register")}


activeOpacity={0.8}>

<Text style={[Link]}>Go to Register</Text>

</TouchableOpacity>

</View>

);

const styles = [Link]({

container: { flex: 1, justifyContent: "center", padding: 20, backgroundColor: "#fff" },

input: {

borderWidth: 1,

borderColor: "#ccc",

padding: 12,

marginBottom: 12,

borderRadius: 8,

backgroundColor: "#fff",
color: "#000",

},

title: { fontSize: 24, marginBottom: 20, textAlign: "center", color: "#000" },

primaryButton: {

backgroundColor: "#1e90ff",

paddingVertical: 12,

alignItems: "center",

borderRadius: 12,

marginBottom: 12,

},

primaryButtonText: {

color: "#fff",

fontSize: 16,

fontWeight: "600",

},

secondaryButton: {

backgroundColor: "#f1f5f9",

paddingVertical: 12,

alignItems: "center",

borderRadius: 12,

},

secondaryButtonText: {

color: "#111827",

fontSize: 16,

fontWeight: "600",

},

});

LOGIN CODE
import React, { useState } from "react";

import { View, TextInput, Button, Text, StyleSheet } from "react-native";

import { signInWithEmailAndPassword } from "firebase/auth";

import { auth } from "../firebaseConfig"; // ✅ use your config

export default function Login({ navigation }: any) {

const [email, setEmail] = useState("");

const [password, setPassword] = useState("");

const handleLogin = async () => {

try {

await signInWithEmailAndPassword(auth, email, password);

[Link]("home"); // 👈 go to home screen after login

} catch (error: any) {

alert([Link]);

};

return (

<View style={[Link]}>

<Text style={[Link]}>Login</Text>

<TextInput

style={[Link]}

placeholder="Email"

value={email}

onChangeText={setEmail}

/>

<TextInput

style={[Link]}
placeholder="Password"

secureTextEntry

value={password}

onChangeText={setPassword}

/>

<Button title="Login" onPress={handleLogin} />

<Button

title="Go to Register"

onPress={() => [Link]("register")}

/>

</View>

);

const styles = [Link]({

container: { flex: 1, justifyContent: "center", padding: 20 },

input: { borderWidth: 1, padding: 10, marginBottom: 10, borderRadius: 8 },

title: { fontSize: 24, marginBottom: 20, textAlign: "center" },

});
REGISTER CODE

import React, { useState } from "react";

import { View, TextInput, Text, StyleSheet, TouchableOpacity } from "react-native";

import { createUserWithEmailAndPassword } from "firebase/auth";

import { auth } from "../firebaseConfig";

import { useRouter } from "expo-router";

export default function Register() {

const [email, setEmail] = useState("");

const [password, setPassword] = useState("");

const router = useRouter();

const handleRegister = async () => {

try {

await createUserWithEmailAndPassword(auth, email, password);

[Link]("/home"); // 👈 redirect after register

} catch (error: any) {

[Link]("Register error:", error?.code, error?.message);

alert(`${error?.code || "auth/error"}: ${error?.message || "Unknown error"}`);

};

return (

<View style={[Link]}>

<Text style={[Link]}>Register</Text>

<TextInput

style={[Link]}

placeholder="Email"

placeholderTextColor="#666"

value={email}
onChangeText={setEmail}

/>

<TextInput

style={[Link]}

placeholder="Password"

placeholderTextColor="#666"

secureTextEntry

value={password}

onChangeText={setPassword}

/>

<TouchableOpacity style={[Link]} onPress={handleRegister}


activeOpacity={0.8}>

<Text style={[Link]}>Register</Text>

</TouchableOpacity>

<TouchableOpacity style={[Link]} onPress={() => [Link]()}


activeOpacity={0.8}>

<Text style={[Link]}>Back to Login</Text>

</TouchableOpacity>

</View>

);

const styles = [Link]({

container: { flex: 1, justifyContent: "center", padding: 20, backgroundColor: "#fff" },

input: {

borderWidth: 1,

borderColor: "#ccc",

padding: 12,

marginBottom: 12,

borderRadius: 8,
backgroundColor: "#fff",

color: "#000",

},

title: { fontSize: 24, marginBottom: 20, textAlign: "center", color: "#000" },

primaryButton: {

backgroundColor: "#1e90ff",

paddingVertical: 12,

alignItems: "center",

borderRadius: 12,

marginBottom: 12,

},

primaryButtonText: {

color: "#fff",

fontSize: 16,

fontWeight: "600",

},

secondaryButton: {

backgroundColor: "#f1f5f9",

paddingVertical: 12,

alignItems: "center",

borderRadius: 12,

},

secondaryButtonText: {

color: "#111827",

fontSize: 16,

fontWeight: "600",

},

});

You might also like