diff --git a/components/BottomNav.js b/components/BottomNav.js
index 8724097..a7e2486 100644
--- a/components/BottomNav.js
+++ b/components/BottomNav.js
@@ -11,6 +11,7 @@ import { Home } from "../pages/Home";
import { Settings } from "../pages/Settings";
import { AboutLefty } from "../subpages/AboutLefty";
import { CameraScan } from "../subpages/CameraScan";
+import { CameraLanding } from "../subpages/CameraLanding";
const Tab = createBottomTabNavigator();
const Stack = createNativeStackNavigator();
@@ -99,6 +100,11 @@ export function BottomNav() {
component={CameraScan}
options={{ headerShown: false }}
/>
+
//
);
diff --git a/components/PaginationNav.js b/components/PaginationNav.js
index 23ad14d..5b0e538 100644
--- a/components/PaginationNav.js
+++ b/components/PaginationNav.js
@@ -1,5 +1,5 @@
-import { View, Text } from "react-native";
-import { IconButton } from "react-native-paper";
+import { View } from "react-native";
+import { IconButton, Text } from "react-native-paper";
function PaginationNav({ currentPageNumber, goToPage, maxPageNumber }) {
const deltaPage = (delta) => goToPage(parseInt(currentPageNumber) + delta);
diff --git a/subpages/CameraLanding.js b/subpages/CameraLanding.js
new file mode 100644
index 0000000..542f985
--- /dev/null
+++ b/subpages/CameraLanding.js
@@ -0,0 +1,101 @@
+import React from "react";
+import { SafeAreaView, ScrollView, View } from "react-native";
+import { Button, Text, useTheme } from "react-native-paper";
+import { Icon, Slider } from "@rneui/themed";
+
+import Layout from "../components/Layout";
+
+export const CameraLanding = ({ navigation, route }) => {
+ const theme = useTheme();
+
+ const [value, setValue] = React.useState(80);
+
+ const { currIngredients, newIngredients } = route.params;
+
+ return (
+
+ navigation.goBack()}
+ >
+
+
+ Use the slider below to adjust the sensitivity!
+
+
+
+ ),
+ }}
+ />
+ Sensitivity: {value}%
+
+ {newIngredients.map((ingredient, index) => (
+ = value / 100
+ ? theme.colors.font
+ : theme.colors.secondary,
+ }}
+ variant="bodyLarge"
+ >
+ {index + 1}. {ingredient.name}
+
+ ))}
+
+
+
+
+
+
+ );
+};
diff --git a/subpages/CameraScan.js b/subpages/CameraScan.js
index 129c742..9c5708b 100644
--- a/subpages/CameraScan.js
+++ b/subpages/CameraScan.js
@@ -1,17 +1,23 @@
import { useEffect, useState } from "react";
import { Dimensions, Linking, SafeAreaView, View } from "react-native";
import { Button, Text, useTheme } from "react-native-paper";
+import { Icon } from "@rneui/themed";
+
import * as ImagePicker from "expo-image-picker";
-import { BACKEND_API_URL } from "../config/config";
-import { useAxios } from "../providers/hooks";
-import Layout from "../components/Layout";
+import { BACKEND_API_URL, GOOGLE_API_KEY } from "../config/config";
+import { useAxios, useNotification } from "../providers/hooks";
import { LoadingIcon } from "../components/LoadingIcon";
+import Layout from "../components/Layout";
-export function CameraScan({ navigation }) {
+export function CameraScan({ navigation, route }) {
const theme = useTheme();
const { publicAxios } = useAxios();
+ const { showNotification } = useNotification();
const [isLoading, setIsLoading] = useState(false);
+ const [isCameraLoading, setIsCameraLoading] = useState(false);
+ const [isMediaLoading, setIsMediaLoading] = useState(false);
+ const { currIngredients } = route.params;
const windowHeight = Dimensions.get("window").height;
@@ -30,48 +36,106 @@ export function CameraScan({ navigation }) {
requestPermissions();
}, []);
+ function handleNoIngredients() {
+ showNotification({
+ title: "No ingredients found",
+ description: "Could not find any ingredients in picture",
+ type: "warn",
+ });
+ setIsLoading(false);
+ }
+
async function handlePicture(result) {
setIsLoading(true);
+
+ const googleVisionRes = await fetch(
+ `https://vision.googleapis.com/v1/images:annotate?key=${GOOGLE_API_KEY}`,
+ {
+ method: "POST",
+ body: JSON.stringify({
+ requests: [
+ {
+ image: {
+ content: result.base64,
+ },
+ features: [{ type: "LABEL_DETECTION", maxResults: 15 }],
+ },
+ ],
+ }),
+ }
+ );
+
+ const res = await googleVisionRes.json();
+
+ const detectedIngredients = res.responses[0].labelAnnotations.map(
+ (annotation) => ({
+ name: annotation.description,
+ score: annotation.score,
+ })
+ );
+
+ if (detectedIngredients.length === 0) {
+ return handleNoIngredients();
+ }
+
await publicAxios
.post(`${BACKEND_API_URL}/ingredients`, {
- base64_string: result.base64,
+ ingredients: detectedIngredients,
+ })
+ .then((res) => {
+ if (res.length === 0) {
+ return handleNoIngredients();
+ } else {
+ navigation.navigate("CameraLanding", {
+ newIngredients: res,
+ currIngredients: currIngredients,
+ });
+ }
})
- .then((res) =>
- navigation.navigate("Recipe", {
- ingredients: res.data
- .filter((ingredient) => ingredient.confidence > 75)
- .map((ingredient) => ingredient.name),
- })
- )
.catch((error) => {});
-
setIsLoading(false);
}
- async function takeImage() {
- setIsLoading(true);
- let result = await ImagePicker.launchCameraAsync({
+ function takeImage() {
+ setIsCameraLoading(true);
+ ImagePicker.launchCameraAsync({
base64: true,
quality: 1,
- });
- setIsLoading(false);
-
- if (!result.canceled) {
- await handlePicture(result.assets[0]);
- }
+ })
+ .then((res) => {
+ if (!res.canceled) {
+ handlePicture(res.assets[0]);
+ }
+ })
+ .catch((error) =>
+ showNotification({
+ title: "Failed to open camera",
+ description: error.message,
+ type: "error",
+ })
+ )
+ .finally(() => setIsCameraLoading(false));
}
- async function pickImage() {
- setIsLoading(true);
- let result = await ImagePicker.launchImageLibraryAsync({
+ function pickImage() {
+ setIsMediaLoading(true);
+ ImagePicker.launchImageLibraryAsync({
base64: true,
quality: 1,
- });
- setIsLoading(false);
-
- if (!result.canceled) {
- await handlePicture(result.assets[0]);
- }
+ })
+ .then((res) => {
+ if (!res.canceled) {
+ handlePicture(res.assets[0]);
+ }
+ })
+ .catch((error) =>
+ showNotification({
+ title: "Failed to open image library",
+ description: error.message,
+ type: "error",
+ })
+ )
+ .finally(() => setIsMediaLoading(false));
}
return (
@@ -81,24 +145,67 @@ export function CameraScan({ navigation }) {
onAction={() => navigation.goBack()}
iconName="chevron-left"
>
-
- {isLoading && }
- Upload or take a picture
-
-
-
+ {isLoading ? (
+
+
+
+ ) : (
+
+
+
+
+
+
+ Upload or take a picture
+
+
+
+ )}
);