From b54693caa79786c0a755e2cc1de255c666097bc6 Mon Sep 17 00:00:00 2001 From: Bagasbanuna02 Date: Fri, 4 Jul 2025 15:36:09 +0800 Subject: [PATCH] feature deskripsi: - new component camera --- app.json | 8 + app/(application)/profile/[id]/edit.tsx | 55 ++--- .../profile/[id]/take-picture.tsx | 168 ++++++++++++++++ .../profile/[id]/take-picture2.tsx | 190 ++++++++++++++++++ .../profile/[id]/update-background.tsx | 50 ++++- .../profile/[id]/update-photo.tsx | 40 +++- app/(application)/profile/_layout.tsx | 8 + bun.lock | 8 + components/Button/ButtonCustom.tsx | 6 +- components/Button/ButtonUpload.tsx | 21 ++ components/Camera/CameraCustom.tsx | 0 constants/dummy-image-value.ts | 6 + package.json | 2 + styles/global-styles.ts | 6 + tsconfig.json | 2 +- 15 files changed, 528 insertions(+), 42 deletions(-) create mode 100644 app/(application)/profile/[id]/take-picture.tsx create mode 100644 app/(application)/profile/[id]/take-picture2.tsx create mode 100644 components/Button/ButtonUpload.tsx create mode 100644 components/Camera/CameraCustom.tsx create mode 100644 constants/dummy-image-value.ts diff --git a/app.json b/app.json index a3e8560..3f78fc0 100644 --- a/app.json +++ b/app.json @@ -38,6 +38,14 @@ "resizeMode": "contain", "backgroundColor": "#ffffff" } + ], + [ + "expo-camera", + { + "cameraPermission": "Allow $(PRODUCT_NAME) to access your camera", + "microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone", + "recordAudioAndroid": true + } ] ], "experiments": { diff --git a/app/(application)/profile/[id]/edit.tsx b/app/(application)/profile/[id]/edit.tsx index b799b81..c3f14a2 100644 --- a/app/(application)/profile/[id]/edit.tsx +++ b/app/(application)/profile/[id]/edit.tsx @@ -3,23 +3,22 @@ import { ButtonCustom, SelectCustom, StackCustom, - TextCustom, TextInputCustom, ViewWrapper, } from "@/components"; -import { MainColor } from "@/constants/color-palet"; import { router, useLocalSearchParams } from "expo-router"; import { useState } from "react"; -import { StyleSheet, Text } from "react-native"; +import { StyleSheet } from "react-native"; export default function ProfileEdit() { const { id } = useLocalSearchParams(); - const [nama, setNama] = useState("Bagas Banuna"); - const [email, setEmail] = useState("bagasbanuna@gmail.com"); - const [alamat, setAlamat] = useState("Bandar Lampung"); - - const [selectedValue, setSelectedValue] = useState(""); + const [data, setData] = useState({ + nama: "Bagas Banuna", + email: "bagasbanuna@gmail.com", + alamat: "Jember", + selectedValue: "", + }); const options = [ { label: "React", value: "react" }, @@ -33,15 +32,24 @@ export default function ProfileEdit() { { label: "SvelteKit", value: "sveltekit" }, ]; + const handleSave = () => { + console.log({ + nama: data.nama, + email: data.email, + alamat: data.alamat, + selectedValue: data.selectedValue, + }); + router.back(); + }; + return ( { - console.log("data >>", nama, email, alamat, selectedValue); - router.back(); - }} + disabled={ + !data.nama || !data.email || !data.alamat || !data.selectedValue + } + onPress={handleSave} > Simpan @@ -52,37 +60,36 @@ export default function ProfileEdit() { label="Framework" placeholder="Pilih framework favoritmu" data={options} - value={selectedValue} - onChange={setSelectedValue} + value={data.selectedValue} + onChange={(value) => { + setData({ ...(data as any), selectedValue: value }); + }} /> - {/* {selectedValue && ( - Terpilih: {selectedValue} - )} */} { - setNama(text); + setData({ ...data, nama: text }); }} required /> { - setEmail(text); + setData({ ...data, email: text }); }} required /> { - setAlamat(text); + setData({ ...data, alamat: text }); }} required /> diff --git a/app/(application)/profile/[id]/take-picture.tsx b/app/(application)/profile/[id]/take-picture.tsx new file mode 100644 index 0000000..1148230 --- /dev/null +++ b/app/(application)/profile/[id]/take-picture.tsx @@ -0,0 +1,168 @@ +import { + ButtonCustom, + Spacing, + StackCustom, + ViewWrapper +} from "@/components"; +import AntDesign from "@expo/vector-icons/AntDesign"; +import FontAwesome6 from "@expo/vector-icons/FontAwesome6"; +import { CameraType, CameraView, useCameraPermissions } from "expo-camera"; +import { Image } from "expo-image"; +import * as ImagePicker from "expo-image-picker"; +import { router } from "expo-router"; +import { useRef, useState } from "react"; +import { Pressable, StyleSheet, Text, View } from "react-native"; + +export default function TakePictureProfile() { + const [permission, requestPermission] = useCameraPermissions(); + const ref = useRef(null); + const [uri, setUri] = useState(null); + const [facing, setFacing] = useState("back"); + + if (!permission?.granted) { + return ( + + + We need your permission to use the camera + + + Grant permission + + + ); + } + + const takePicture = async () => { + const photo = await ref.current?.takePictureAsync(); + setUri(photo?.uri || null); + }; + + const pickImage = async () => { + const result = await ImagePicker.launchImageLibraryAsync({ + mediaTypes: ImagePicker.MediaTypeOptions.Images, + allowsEditing: true, + aspect: [1, 1], + quality: 1, + }); + + if (!result.canceled) { + setUri(result.assets[0].uri); + } + }; + + const toggleFacing = () => { + setFacing((prev) => (prev === "back" ? "front" : "back")); + }; + + const renderPicture = () => { + return ( + + + + + + setUri(null)} title="Foto ulang" /> + { + console.log("Update foto"); + router.back(); + }} + title="Update Foto" + /> + + + ); + }; + + const renderCameraUI = () => { + return ( + + + + + + + + {({ pressed }) => ( + + + + )} + + + + + + + + ); + }; + + return ( + <> + {uri ? ( + + {renderPicture()} + + ) : ( + <> + + {renderCameraUI()} + + )} + + ); +} + +const styles = StyleSheet.create({ + container: { + justifyContent: "center", + alignItems: "center", + }, + camera: { + flex: 1, + width: "100%", + }, + cameraOverlay: { + ...StyleSheet.absoluteFillObject, + justifyContent: "flex-end", + padding: 44, + }, + shutterContainer: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + }, + shutterBtn: { + backgroundColor: "transparent", + borderWidth: 5, + borderColor: "white", + width: 85, + height: 85, + borderRadius: 45, + alignItems: "center", + justifyContent: "center", + }, + shutterBtnInner: { + width: 70, + height: 70, + borderRadius: 50, + backgroundColor: "white", + }, +}); diff --git a/app/(application)/profile/[id]/take-picture2.tsx b/app/(application)/profile/[id]/take-picture2.tsx new file mode 100644 index 0000000..8483dde --- /dev/null +++ b/app/(application)/profile/[id]/take-picture2.tsx @@ -0,0 +1,190 @@ +// COMPONENT : Jika ingin uoload gambar dan video gunakan component ini + +import { + ButtonCustom, + Spacing, + StackCustom, + ViewWrapper +} from "@/components"; +import AntDesign from "@expo/vector-icons/AntDesign"; +import Feather from "@expo/vector-icons/Feather"; +import FontAwesome6 from "@expo/vector-icons/FontAwesome6"; +import { + CameraMode, + CameraType, + CameraView, + useCameraPermissions, +} from "expo-camera"; +import { Image } from "expo-image"; +import { router } from "expo-router"; +import { useRef, useState } from "react"; +import { Button, Pressable, StyleSheet, Text, View } from "react-native"; + +export default function TakePictureProfile2() { + const [permission, requestPermission] = useCameraPermissions(); + const ref = useRef(null); + const [uri, setUri] = useState(null); + const [mode, setMode] = useState("picture"); + const [facing, setFacing] = useState("back"); + const [recording, setRecording] = useState(false); + + if (!permission?.granted) { + return ( + + + We need your permission to use the camera + +