diff --git a/hmns-app/client/app/(tabs)/index.tsx b/hmns-app/client/app/(tabs)/index.tsx
index a293c0d..4b731d0 100644
--- a/hmns-app/client/app/(tabs)/index.tsx
+++ b/hmns-app/client/app/(tabs)/index.tsx
@@ -3,33 +3,43 @@ import { StyleSheet } from "react-native";
import EditScreenInfo from "../../components/EditScreenInfo";
import { Text, View } from "../../components/Themed";
-export default function TabOneScreen () {
+export default function TabOneScreen() {
return (
- Tab One
-
-
+
+ Tab One
+
+
+
);
}
-
+
const styles = StyleSheet.create({
container: {
- alignItems: "center",
flex: 1,
- justifyContent: "center"
+ },
+ header: {
+ alignItems: "center",
+ justifyContent: "center",
+ // Adjust the flex value or height as needed
+ flex: 0.45,
},
separator: {
height: 1,
marginVertical: 30,
- width: "80%"
+ width: "80%",
},
title: {
fontSize: 20,
- fontWeight: "bold"
- }
+ fontWeight: "bold",
+ },
+ camera: {
+ flex: 1, // Take up all available space
+ },
});
+
diff --git a/hmns-app/client/app/(tabs)/two.tsx b/hmns-app/client/app/(tabs)/two.tsx
index 15d9ff8..88cb8d4 100644
--- a/hmns-app/client/app/(tabs)/two.tsx
+++ b/hmns-app/client/app/(tabs)/two.tsx
@@ -1,31 +1,17 @@
import { StyleSheet } from "react-native";
+import CameraComponent from "../../components/CameraComponent";
+import { View } from "../../components/Themed";
-import EditScreenInfo from "../../components/EditScreenInfo";
-import { Text, View } from "../../components/Themed";
-
-export default function TabTwoScreen () {
+export default function TabTwoScreen() {
return (
- Tab Two
-
-
+
);
}
const styles = StyleSheet.create({
container: {
- alignItems: "center",
flex: 1,
- justifyContent: "center"
- },
- separator: {
- height: 1,
- marginVertical: 30,
- width: "80%"
},
- title: {
- fontSize: 20,
- fontWeight: "bold"
- }
});
diff --git a/hmns-app/client/babel.config.js b/hmns-app/client/babel.config.js
index a297226..241abcd 100644
--- a/hmns-app/client/babel.config.js
+++ b/hmns-app/client/babel.config.js
@@ -1,10 +1,10 @@
module.exports = function (api) {
- api.cache(true);
- return {
- presets: ['babel-preset-expo'],
- plugins: [
- // Required for expo-router
- 'expo-router/babel',
- ],
- };
+ api.cache(true);
+ return {
+ presets: ["babel-preset-expo"],
+ plugins: [
+ // Required for expo-router
+ "expo-router/babel",
+ ],
+ };
};
diff --git a/hmns-app/client/components/.CameraComponent.tsx.swo b/hmns-app/client/components/.CameraComponent.tsx.swo
new file mode 100644
index 0000000..36ef9b4
Binary files /dev/null and b/hmns-app/client/components/.CameraComponent.tsx.swo differ
diff --git a/hmns-app/client/components/CameraComponent.tsx b/hmns-app/client/components/CameraComponent.tsx
new file mode 100644
index 0000000..52a8a8a
--- /dev/null
+++ b/hmns-app/client/components/CameraComponent.tsx
@@ -0,0 +1,241 @@
+import React, { useState, useEffect, useRef } from "react";
+import { View, Text, StyleSheet, TouchableOpacity, Image } from "react-native";
+import { Camera } from "expo-camera";
+// import { Ionicons } from "@expo/vector-icons";
+import * as MediaLibrary from "expo-media-library";
+import { StatusBar } from "react-native";
+
+export default function CameraComponent() {
+ const [hasPermission, setHasPermission] = useState(null);
+ // // State to manage the type of camera (front or back)
+ // const [type, setType] = useState(Camera.Constants.Type.back);
+ // State to store the captured photo
+ const [photo, setPhoto] = useState(null);
+ // Reference to the camera component
+ const cameraRef = useRef(null);
+ // Function to show photo-taking tips
+ const showPhotoTips = () => {
+ alert("Photo-taking Tips:\n1. Keep your hands steady.\n2. Make sure there's enough light.\n3. Focus on the butterfly you want to search up before taking the photo.");
+ };
+ const [confirmVisible, setConfirmVisible] = useState(false);
+
+ // Request camera permissions when the component mounts
+ useEffect(() => {
+ (async () => {
+ // Request camera permission
+ const cameraStatus = await Camera.requestCameraPermissionsAsync();
+ setHasPermission(cameraStatus.status === "granted");
+
+ // Request media library permission
+ const mediaLibraryStatus = await MediaLibrary.requestPermissionsAsync();
+ if (mediaLibraryStatus.status !== "granted") {
+ alert("Sorry, we need camera roll permissions to save the image!");
+ }
+ })();
+ }, []);
+
+ // // Capture a photo and save it to photo album
+ // const takePhoto = async () => {
+ // if (cameraRef.current) {
+ // const options = { quality: 0.5, base64: true, skipProcessing: true };
+ // let newPhoto = await cameraRef.current.takePictureAsync(options);
+ // setPhoto(newPhoto);
+
+ // // Save the photo to the gallery
+ // const asset = await MediaLibrary.createAssetAsync(newPhoto.uri);
+ // await MediaLibrary.createAlbumAsync('HMNS', asset, false); // Replace 'YourAppName' with your app's name or any other desired album name.
+ // }
+ // };
+ const takePhoto = async () => {
+ if (cameraRef.current) {
+ const options = { quality: 0.5, base64: true, skipProcessing: true };
+ const newPhoto = await cameraRef.current.takePictureAsync(options);
+ setPhoto(newPhoto);
+ setConfirmVisible(true); // Show the confirmation screen
+ }
+ };
+
+ // Retake the photo
+ const retakePhoto = () => {
+ setPhoto(null);
+ setConfirmVisible(false); // Hide the confirmation screen
+ };
+
+ // Accept the photo and save it
+ const acceptPhoto = async () => {
+ if (photo) {
+ try {
+ // Save the photo to the gallery here
+ const asset = await MediaLibrary.createAssetAsync(photo.uri);
+ await MediaLibrary.createAlbumAsync("YourAppName", asset, false);
+
+ // Handle any operation after saving the photo, such as navigation or state reset
+ setConfirmVisible(false); // Hide confirmation screen
+ setPhoto(null); // Reset photo state
+ } catch (error) {
+ // Handle any errors here
+ console.error("Error saving photo", error);
+ alert("Error saving photo");
+ }
+ }
+ };
+
+ // If confirmation screen should be visible, show the taken photo and options
+ if (confirmVisible && photo) {
+ return (
+
+
+
+
+ Retake
+
+
+ Accept
+
+
+
+ );
+ }
+
+
+
+ // If permissions are still being requested, return an empty view
+ if (hasPermission === null) {
+ return ;
+ }
+ // If camera access is denied, inform the user
+ if (hasPermission === false) {
+ return No access to camera;
+ }
+
+ // Make sure to hide the status bar to provide a full-screen experience
+ StatusBar.setHidden(true);
+
+ return (
+
+
+ {/* Overlay the UI components on the camera preview */}
+
+
+ {/* You can add additional icons or information at the top */}
+
+
+
+ {/* Placeholder for gallery button/icon */}
+ {photo && (
+
+
+
+ )}
+
+
+
+ Tips
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: "black",
+ },
+ camera: {
+ flex: 1,
+ justifyContent: "space-between",
+ },
+ uiContainer: {
+ flex: 1,
+ backgroundColor: "transparent",
+ flexDirection: "column",
+ justifyContent: "space-between",
+ },
+ topToolbar: {
+ flex: 0.1,
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "flex-start",
+ paddingTop: 20,
+ paddingHorizontal: 20,
+ },
+ bottomToolbar: {
+ padding: 20,
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+ },
+ captureButton: {
+ width: 70,
+ height: 70,
+ borderWidth: 4,
+ borderColor: "white",
+ borderRadius: 35,
+ backgroundColor: "white",
+ alignSelf: "center",
+ },
+ flipButton: {
+ alignSelf: "center",
+ flex: 0.1,
+ alignItems: "center",
+ },
+ galleryButton: {
+ width: 50,
+ height: 50,
+ borderRadius: 10,
+ alignSelf: "center",
+ overflow: "hidden",
+ },
+ thumbnail: {
+ width: 50,
+ height: 50,
+ },
+ tipsButton: {
+ // Style your button as needed
+ backgroundColor: "rgba(255, 255, 255, 0.5)",
+ borderRadius: 10,
+ padding: 10,
+ },
+ tipsButtonText: {
+ color: "white",
+ fontSize: 18,
+ },
+ confirmContainer: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ },
+ confirmButtons: {
+ flexDirection: "row",
+ justifyContent: "space-around",
+ width: "100%",
+ padding: 20,
+ },
+ confirmButton: {
+ flex: 1,
+ alignItems: "center",
+ justifyContent: "center",
+ marginHorizontal: 10,
+ paddingVertical: 10,
+ borderRadius: 5,
+ backgroundColor: "rgba(0,0,0,0.5)",
+ },
+ preview: {
+ width: "100%", // You may need to adjust this
+ height: "80%", // You may need to adjust this
+ borderRadius: 4,
+ },
+ confirmButtonText: {
+ // Style for the text inside your confirm buttons
+ color: "white",
+ fontSize: 18,
+ textAlign: "center",
+ },
+});
+
diff --git a/hmns-app/client/components/EditScreenInfo.tsx b/hmns-app/client/components/EditScreenInfo.tsx
index 12bebe9..6ab103a 100644
--- a/hmns-app/client/components/EditScreenInfo.tsx
+++ b/hmns-app/client/components/EditScreenInfo.tsx
@@ -1,77 +1,77 @@
-import React from 'react';
-import { StyleSheet } from 'react-native';
+import React from "react";
+import { StyleSheet } from "react-native";
-import Colors from '../constants/Colors';
-import { ExternalLink } from './ExternalLink';
-import { MonoText } from './StyledText';
-import { Text, View } from './Themed';
+import Colors from "../constants/Colors";
+import { ExternalLink } from "./ExternalLink";
+import { MonoText } from "./StyledText";
+import { Text, View } from "./Themed";
export default function EditScreenInfo({ path }: { path: string }) {
- return (
-
-
-
+ return (
+
+
+
Open up the code for this screen:
-
+
-
- {path}
-
+
+ {path}
+
-
+
Change any of the text, save the file, and your app will automatically update.
-
-
+
+
-
-
-
- Tap here if your app doesn't automatically update after making changes
-
-
-
-
- );
+
+
+
+ Tap here if your app doesnt automatically update after making changes
+
+
+
+
+ );
}
const styles = StyleSheet.create({
- getStartedContainer: {
- alignItems: 'center',
- marginHorizontal: 50,
- },
- homeScreenFilename: {
- marginVertical: 7,
- },
- codeHighlightContainer: {
- borderRadius: 3,
- paddingHorizontal: 4,
- },
- getStartedText: {
- fontSize: 17,
- lineHeight: 24,
- textAlign: 'center',
- },
- helpContainer: {
- marginTop: 15,
- marginHorizontal: 20,
- alignItems: 'center',
- },
- helpLink: {
- paddingVertical: 15,
- },
- helpLinkText: {
- textAlign: 'center',
- },
+ getStartedContainer: {
+ alignItems: "center",
+ marginHorizontal: 50,
+ },
+ homeScreenFilename: {
+ marginVertical: 7,
+ },
+ codeHighlightContainer: {
+ borderRadius: 3,
+ paddingHorizontal: 4,
+ },
+ getStartedText: {
+ fontSize: 17,
+ lineHeight: 24,
+ textAlign: "center",
+ },
+ helpContainer: {
+ marginTop: 15,
+ marginHorizontal: 20,
+ alignItems: "center",
+ },
+ helpLink: {
+ paddingVertical: 15,
+ },
+ helpLinkText: {
+ textAlign: "center",
+ },
});
diff --git a/hmns-app/client/components/ExternalLink.tsx b/hmns-app/client/components/ExternalLink.tsx
index c535be9..397a61e 100644
--- a/hmns-app/client/components/ExternalLink.tsx
+++ b/hmns-app/client/components/ExternalLink.tsx
@@ -1,28 +1,28 @@
-import { Link } from 'expo-router';
-import * as WebBrowser from 'expo-web-browser';
-import React from 'react';
-import { Platform } from 'react-native';
+import { Link } from "expo-router";
+import * as WebBrowser from "expo-web-browser";
+import React from "react";
+import { Platform } from "react-native";
export function ExternalLink(
- props: Omit, 'href'> & { href: string }
+ props: Omit, "href"> & { href: string }
) {
- return (
- {
- if (Platform.OS !== 'web') {
- // Prevent the default behavior of linking to the default browser on native.
- e.preventDefault();
- // Open the link in an in-app browser.
- WebBrowser.openBrowserAsync(props.href as string);
- }
- }}
- />
- );
+ return (
+ {
+ if (Platform.OS !== "web") {
+ // Prevent the default behavior of linking to the default browser on native.
+ e.preventDefault();
+ // Open the link in an in-app browser.
+ WebBrowser.openBrowserAsync(props.href as string);
+ }
+ }}
+ />
+ );
}
diff --git a/hmns-app/client/components/StyledText.tsx b/hmns-app/client/components/StyledText.tsx
index aa3977c..b064091 100644
--- a/hmns-app/client/components/StyledText.tsx
+++ b/hmns-app/client/components/StyledText.tsx
@@ -1,5 +1,5 @@
-import { Text, TextProps } from './Themed';
+import { Text, TextProps } from "./Themed";
export function MonoText(props: TextProps) {
- return ;
+ return ;
}
diff --git a/hmns-app/client/components/Themed.tsx b/hmns-app/client/components/Themed.tsx
index 6399846..9b9e02a 100644
--- a/hmns-app/client/components/Themed.tsx
+++ b/hmns-app/client/components/Themed.tsx
@@ -3,42 +3,42 @@
* https://docs.expo.io/guides/color-schemes/
*/
-import { Text as DefaultText, useColorScheme, View as DefaultView } from 'react-native';
+import { Text as DefaultText, useColorScheme, View as DefaultView } from "react-native";
-import Colors from '../constants/Colors';
+import Colors from "../constants/Colors";
type ThemeProps = {
lightColor?: string;
darkColor?: string;
};
-export type TextProps = ThemeProps & DefaultText['props'];
-export type ViewProps = ThemeProps & DefaultView['props'];
+export type TextProps = ThemeProps & DefaultText["props"];
+export type ViewProps = ThemeProps & DefaultView["props"];
export function useThemeColor(
- props: { light?: string; dark?: string },
- colorName: keyof typeof Colors.light & keyof typeof Colors.dark
+ props: { light?: string; dark?: string },
+ colorName: keyof typeof Colors.light & keyof typeof Colors.dark
) {
- const theme = useColorScheme() ?? 'light';
- const colorFromProps = props[theme];
-
- if (colorFromProps) {
- return colorFromProps;
- } else {
- return Colors[theme][colorName];
- }
+ const theme = useColorScheme() ?? "light";
+ const colorFromProps = props[theme];
+
+ if (colorFromProps) {
+ return colorFromProps;
+ } else {
+ return Colors[theme][colorName];
+ }
}
export function Text(props: TextProps) {
- const { style, lightColor, darkColor, ...otherProps } = props;
- const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
+ const { style, lightColor, darkColor, ...otherProps } = props;
+ const color = useThemeColor({ light: lightColor, dark: darkColor }, "text");
- return ;
+ return ;
}
export function View(props: ViewProps) {
- const { style, lightColor, darkColor, ...otherProps } = props;
- const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
+ const { style, lightColor, darkColor, ...otherProps } = props;
+ const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, "background");
- return ;
+ return ;
}
diff --git a/hmns-app/client/components/__tests__/StyledText-test.js b/hmns-app/client/components/__tests__/StyledText-test.js
deleted file mode 100644
index f569ce8..0000000
--- a/hmns-app/client/components/__tests__/StyledText-test.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import * as React from 'react';
-import renderer from 'react-test-renderer';
-
-import { MonoText } from '../StyledText';
-
-it(`renders correctly`, () => {
- const tree = renderer.create(Snapshot test!).toJSON();
-
- expect(tree).toMatchSnapshot();
-});
diff --git a/hmns-app/client/constants/Colors.ts b/hmns-app/client/constants/Colors.ts
index 1c706c7..3a81a77 100644
--- a/hmns-app/client/constants/Colors.ts
+++ b/hmns-app/client/constants/Colors.ts
@@ -1,19 +1,19 @@
-const tintColorLight = '#2f95dc';
-const tintColorDark = '#fff';
+const tintColorLight = "#2f95dc";
+const tintColorDark = "#fff";
export default {
- light: {
- text: '#000',
- background: '#fff',
- tint: tintColorLight,
- tabIconDefault: '#ccc',
- tabIconSelected: tintColorLight,
- },
- dark: {
- text: '#fff',
- background: '#000',
- tint: tintColorDark,
- tabIconDefault: '#ccc',
- tabIconSelected: tintColorDark,
- },
+ light: {
+ text: "#000",
+ background: "#fff",
+ tint: tintColorLight,
+ tabIconDefault: "#ccc",
+ tabIconSelected: tintColorLight,
+ },
+ dark: {
+ text: "#fff",
+ background: "#000",
+ tint: tintColorDark,
+ tabIconDefault: "#ccc",
+ tabIconSelected: tintColorDark,
+ },
};
diff --git a/hmns-app/client/metro.config.js b/hmns-app/client/metro.config.js
index c5033a3..8fb7b51 100644
--- a/hmns-app/client/metro.config.js
+++ b/hmns-app/client/metro.config.js
@@ -1,10 +1,11 @@
+/* eslint-disable */
// Learn more https://docs.expo.io/guides/customizing-metro
-const { getDefaultConfig } = require('expo/metro-config');
+const {getDefaultConfig} = require("expo/metro-config");
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname, {
- // [Web-only]: Enables CSS support in Metro.
- isCSSEnabled: true,
+ // [Web-only]: Enables CSS support in Metro.
+ isCSSEnabled: true,
});
module.exports = config;
diff --git a/hmns-app/client/package-lock.json b/hmns-app/client/package-lock.json
index 45f9406..b5d63ef 100644
--- a/hmns-app/client/package-lock.json
+++ b/hmns-app/client/package-lock.json
@@ -13,8 +13,10 @@
"@react-navigation/native": "^6.0.2",
"@types/react": "~18.2.14",
"expo": "~49.0.13",
+ "expo-camera": "~13.4.4",
"expo-font": "~11.4.0",
"expo-linking": "~5.0.2",
+ "expo-media-library": "~15.4.1",
"expo-router": "^2.0.0",
"expo-splash-screen": "~0.20.5",
"expo-status-bar": "~1.6.0",
@@ -6545,6 +6547,17 @@
"url-parse": "^1.5.9"
}
},
+ "node_modules/expo-camera": {
+ "version": "13.4.4",
+ "resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-13.4.4.tgz",
+ "integrity": "sha512-7k54APbpSulUDR2CrD5SrmKjCdfdg4tqKRpbBOKc2J2MIBHhunExU77435JDYSejHRY5bfRHZsEp3yKwR862uw==",
+ "dependencies": {
+ "invariant": "^2.2.4"
+ },
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
"node_modules/expo-constants": {
"version": "14.4.2",
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-14.4.2.tgz",
@@ -6612,6 +6625,14 @@
"url-parse": "^1.5.9"
}
},
+ "node_modules/expo-media-library": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/expo-media-library/-/expo-media-library-15.4.1.tgz",
+ "integrity": "sha512-lpWcT4pynWcE7TyNMUkLFH4YcueCTnq7UOJYRR0vewPEJeQXwRscka7zBtrhA+RSsJda013Q0615K+5lRLt14Q==",
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
"node_modules/expo-modules-autolinking": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.5.1.tgz",
diff --git a/hmns-app/client/package.json b/hmns-app/client/package.json
index 10d3428..ed922ea 100644
--- a/hmns-app/client/package.json
+++ b/hmns-app/client/package.json
@@ -7,7 +7,8 @@
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
- "test": "jest --watchAll"
+ "test": "jest --watchAll",
+ "lint": "eslint --fix ."
},
"dependencies": {
"@apollo/client": "^3.8.5",
@@ -29,6 +30,8 @@
"react-native-screens": "~3.22.0",
"react-native-web": "~0.19.6",
"typescript": "^5.1.3",
- "@types/react": "~18.2.14"
+ "@types/react": "~18.2.14",
+ "expo-camera": "~13.4.4",
+ "expo-media-library": "~15.4.1"
}
}