From f22de8150d48a13be987170480573c50eb705da3 Mon Sep 17 00:00:00 2001 From: Andrii Solianyk Date: Fri, 23 May 2025 19:36:51 +0200 Subject: [PATCH] =?UTF-8?q?Pobieranie=20i=20wysy=C5=82anie=20zdj=C4=99?= =?UTF-8?q?=C4=87=20i=20GPS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/locations.jsx | 20 +-- app.json | 6 + app/(tabs)/add.jsx | 66 ++++++-- app/location/[id].jsx | 6 +- app/location/edit/[id].jsx | 334 ++++++++++++++++++++----------------- package.json | 1 + 6 files changed, 254 insertions(+), 179 deletions(-) diff --git a/api/locations.jsx b/api/locations.jsx index 5c03e50..a7290c9 100644 --- a/api/locations.jsx +++ b/api/locations.jsx @@ -1,6 +1,6 @@ import axios from "axios"; -const API_URL = "https://hopp.zikor.pl"; +const API_URL = "http://192.168.0.118:9000"; export async function listLocations() { try { @@ -9,7 +9,6 @@ export async function listLocations() { return "No locations found"; } - // Нормализуем изображения в полученных данных return response.data.map(location => ({ ...location, imageSource: normalizeImageSource(location.image) @@ -23,23 +22,18 @@ export async function listLocations() { const normalizeImageSource = (image) => { if (!image) return null; - // Проверка, является ли изображение URL if (typeof image === 'string') { - // Если строка начинается с http или https, это URL if (image.startsWith('http://') || image.startsWith('https://')) { return { uri: image }; } - // Проверка на base64 if (image.startsWith('data:image')) { return { uri: image }; } else if (image.length > 100) { - // Предполагаем, что это base64 без префикса return { uri: `data:image/jpeg;base64,${image}` }; } } - // Возвращаем null для неправильного формата return null; } @@ -47,7 +41,8 @@ export async function getLocation(id) { try { const location = await axios.get(`${API_URL}/locations/${id}`); if (!location) { - throw new Error("Location not found"); + console.error("Could not find location"); + return("Location not found"); } return [...location.data, {image: normalizeImageSource(location.image)}]; @@ -65,7 +60,8 @@ export async function addLocation(location) { }, }); if (!response) { - throw new Error("Failed to add location"); + console.log("Error adding location"); + return("Failed to add location"); } return response.data; } catch (error) { @@ -80,7 +76,8 @@ export async function updateLocation(id, location) { headers: { "Content-Type": "application/json" }, }); if (!response) { - throw new Error("Failed to add location"); + console.log("Failed to update location"); + return("Failed to update location"); } return response.data; } catch (error) { @@ -93,7 +90,8 @@ export async function deleteLocation(id) { try { const response = await axios.delete(`${API_URL}/locations/${id}`); if (!response) { - throw new Error("Failed to delete location"); + console.log("Error deleting location"); + return("Failed to delete location"); } return response.data; } catch (error) { diff --git a/app.json b/app.json index c711f61..2c64be6 100644 --- a/app.json +++ b/app.json @@ -33,6 +33,12 @@ { "photosPermission": "The app accesses your photos to let you share them with your friends." } + ], + [ + "expo-location", + { + "locationAlwaysAndWhenInUsePermission": "Allow $(PRODUCT_NAME) to use your location." + } ] ] } diff --git a/app/(tabs)/add.jsx b/app/(tabs)/add.jsx index 1c76fe9..37dfea9 100644 --- a/app/(tabs)/add.jsx +++ b/app/(tabs)/add.jsx @@ -6,9 +6,11 @@ import { ScrollView, Image, View, + Alert, } from "react-native"; -import {TextInput, Button, Snackbar, Text} from "react-native-paper"; +import {TextInput, Button, Snackbar, Text, useTheme} from "react-native-paper"; import {requestCameraPermissionsAsync, launchCameraAsync} from 'expo-image-picker'; +import * as Location from 'expo-location'; import useLocationStore from "@/locationStore"; export default function FormScreen() { @@ -18,11 +20,15 @@ export default function FormScreen() { image: "", area: 0, population: 0, + latitude: 0, + longitude: 0, }); const [message, setMessage] = useState(""); const [visible, setVisible] = useState(false); const [picture, setPicture] = useState(null); - const [imageMethod, setImageMethod] = useState(null); // null, 'link' или 'camera' + const [imageMethod, setImageMethod] = useState(null); + const [location, setLocation] = useState < Location.LocationObject | null > (null); + const theme = useTheme(); const addLocation = useLocationStore((state) => state.addLocation); @@ -32,7 +38,9 @@ export default function FormScreen() { formData.description && formData.image && formData.area && - formData.population + formData.population && + formData.latitude && + formData.longitude ) { const newLocation = { id: Date.now(), @@ -41,6 +49,8 @@ export default function FormScreen() { image: formData.image, area: parseFloat(formData.area), population: parseInt(formData.population), + latitude: parseFloat(formData.latitude), + longitude: parseFloat(formData.longitude), }; const added = await addLocation(newLocation); @@ -50,6 +60,8 @@ export default function FormScreen() { image: "", area: 0, population: 0, + latitude: 0, + longitude: 0 }); setPicture(null); setImageMethod(null); @@ -83,11 +95,36 @@ export default function FormScreen() { if (!result.canceled && result.assets && result.assets.length > 0) { const image = result.assets[0]; setPicture(image.uri); - console.log(image.base64); setFormData({...formData, image: image.base64}); } } + async function getCurrentLocation() { + + let {status} = await Location.requestForegroundPermissionsAsync(); + if (status !== 'granted') { + console.log('Permission to access location was denied'); + Alert.alert("Błąd", "Nie udało się uzyskać dostępu do pobierania lokalizacji"); + return; + } + + try { + let location = await Location.getCurrentPositionAsync({}); + setLocation(location); + setFormData({ + ...formData, + latitude: location.coords.latitude, + longitude: location.coords.longitude + }); + Alert.alert("Sukces!", "Pobrano lokalizację\n" + + "Szerokość geograficzna: " + location.coords.latitude + "\n" + + "Długość geograficzna: " + location.coords.longitude); + } catch (error) { + Alert.alert("Błąd", "Nie udało się pobrać lokalizacji"); + console.error(error); + } + } + const selectImageMethod = (method) => { setImageMethod(method); if (method === 'camera') { @@ -103,7 +140,9 @@ export default function FormScreen() { style={{flex: 1}} behavior={Platform.OS === "ios" ? "padding" : "height"} > - + setVisible(false)} @@ -111,7 +150,7 @@ export default function FormScreen() { > {message} - Jak chcesz dodać zdjęcie? + Jak chcesz dodać zdjęcie? + + ); @@ -200,11 +247,10 @@ export default function FormScreen() { const styles = StyleSheet.create({ container: { - flex: 1, - backgroundColor: "#25292e", - justifyContent: "flex-start", + // backgroundColor: "#25292e", alignItems: "center", padding: 10, + flexGrow: 1, }, imageContainer: { width: "100%", @@ -215,7 +261,6 @@ const styles = StyleSheet.create({ width: 150, height: 150, borderStyle: "solid", - borderColor: "#fff", borderWidth: 1, borderRadius: 5, }, @@ -232,7 +277,6 @@ const styles = StyleSheet.create({ label: { marginTop: 10, marginBottom: 10, - color: "#fff", verticalAlign: "middle", textAlign: "center", } diff --git a/app/location/[id].jsx b/app/location/[id].jsx index 683cd19..74643e9 100644 --- a/app/location/[id].jsx +++ b/app/location/[id].jsx @@ -28,7 +28,7 @@ export default function Location() { } return ( - + Ludność: {location.population} osób + + Współrzedne geograficzne: {location.latitude}, {location.longitude} + @@ -67,7 +70,6 @@ const styles = StyleSheet.create({ flex: 1, backgroundColor: "#25292e", justifyContent: "center", - alignItems: "center", }, text: { color: "#fff", diff --git a/app/location/edit/[id].jsx b/app/location/edit/[id].jsx index faf6442..a85ed5e 100644 --- a/app/location/edit/[id].jsx +++ b/app/location/edit/[id].jsx @@ -1,171 +1,195 @@ -import { useState, useEffect } from "react"; +import {useState, useEffect} from "react"; import { - StyleSheet, - Platform, - ScrollView, - KeyboardAvoidingView, - View, - ActivityIndicator, + StyleSheet, + Platform, + ScrollView, + KeyboardAvoidingView, + View, + ActivityIndicator, } from "react-native"; -import { TextInput, Button, Snackbar, useTheme } from "react-native-paper"; -import { useLocalSearchParams, useRouter } from "expo-router"; +import {TextInput, Button, Snackbar, useTheme} from "react-native-paper"; +import {useLocalSearchParams, useRouter} from "expo-router"; import useLocationStore from "@/locationStore"; export default function EditLocation() { - const theme = useTheme(); - const { id } = useLocalSearchParams(); - const router = useRouter(); - const [loading, setLoading] = useState(true); - const [formData, setFormData] = useState({ - name: "", - description: "", - image: "", - area: "", - population: "", - }); + const theme = useTheme(); + const {id} = useLocalSearchParams(); + const router = useRouter(); + const [loading, setLoading] = useState(true); + const [formData, setFormData] = useState({ + name: "", + description: "", + image: "", + area: "", + population: "", + longitude: "", + latitude: "", + }); - const [message, setMessage] = useState(""); - const [visible, setVisible] = useState(false); + const [message, setMessage] = useState(""); + const [visible, setVisible] = useState(false); - const updateLocation = useLocationStore((state) => state.updateLocation); - const getLocation = useLocationStore((state) => state.getLocation); + const updateLocation = useLocationStore((state) => state.updateLocation); + const getLocation = useLocationStore((state) => state.getLocation); - useEffect(() => { - const data = getLocation(id); - if (data) { - setFormData({ - name: data.name, - description: data.description, - image: data.image, - area: data.area.toString(), - population: data.population.toString(), - }); + useEffect(() => { + const data = getLocation(id); + if (data) { + setFormData({ + name: data.name, + description: data.description, + image: data.image, + area: data.area.toString(), + population: data.population.toString(), + longitude: data.longitude.toString(), + latitude: data.latitude.toString(), + }); + } + setLoading(false); + }, [id, getLocation]); + + const handleEditLocation = async () => { + if ( + formData.name && + formData.description && + formData.image && + formData.area && + formData.population && + formData.longitude && + formData.latitude + ) { + // console.log("Form data:", formData); + const response = await updateLocation(id, { + name: formData.name, + description: formData.description, + image: formData.image, + area: parseFloat(formData.area), + population: parseInt(formData.population, 10), + }); + + if (response) { + setMessage("Lokalizacja została zaktualizowana!"); + setVisible(true); + // while (router.canGoBack()) { + // Pop from stack until one element is left + // router.back(); + // } + setTimeout(() => { + router.replace("/"); + }, 300); // Replace the last remaining stack element + } else { + setMessage("Wystąpił błąd podczas aktualizacji lokalizacji!"); + setVisible(true); + } + } else { + setMessage("Wypełnij wszystkie pola!"); + setVisible(true); + } + }; + + if (loading) { + return ( + + + + ); } - setLoading(false); - }, [id, getLocation]); - const handleEditLocation = async () => { - if ( - formData.name && - formData.description && - formData.image && - formData.area && - formData.population - ) { - // console.log("Form data:", formData); - const response = await updateLocation(id, { - name: formData.name, - description: formData.description, - image: formData.image, - area: parseFloat(formData.area), - population: parseInt(formData.population, 10), - }); - - if (response) { - setMessage("Lokalizacja została zaktualizowana!"); - setVisible(true); - // while (router.canGoBack()) { - // Pop from stack until one element is left - // router.back(); - // } - setTimeout(() => { - router.replace("/"); - }, 300); // Replace the last remaining stack element - } else { - setMessage("Wystąpił błąd podczas aktualizacji lokalizacji!"); - setVisible(true); - } - } else { - setMessage("Wypełnij wszystkie pola!"); - setVisible(true); - } - }; - - if (loading) { return ( - - - + + + setVisible(false)} + duration={3000} + > + {message} + + setFormData({...formData, name: e})} + /> + setFormData({...formData, description: e})} + /> + setFormData({...formData, image: e})} + /> + setFormData({...formData, area: e})} + /> + setFormData({...formData, population: e})} + /> + setFormData({...formData, longitude: e})} + /> + setFormData({...formData, latitude: e})} + /> + + + ); - } - - return ( - - - setVisible(false)} - duration={3000} - > - {message} - - setFormData({ ...formData, name: e })} - /> - setFormData({ ...formData, description: e })} - /> - setFormData({ ...formData, image: e })} - /> - setFormData({ ...formData, area: e })} - /> - setFormData({ ...formData, population: e })} - /> - - - - ); } const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: "#25292e", - justifyContent: "flex-start", - alignItems: "center", - }, + container: { + flex: 1, + backgroundColor: "#25292e", + justifyContent: "flex-start", + alignItems: "center", + }, }); diff --git a/package.json b/package.json index 54df214..50195d4 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "expo-router": "~5.0.7", "expo-status-bar": "~2.2.3", "expo-image-picker": "~16.1.4", + "expo-location": "~18.1.5", "react": "19.0.0", "react-dom": "19.0.0", "react-native": "0.79.2",