Pobieranie i wysyłanie zdjęć i GPS

This commit is contained in:
2025-05-23 19:36:51 +02:00
parent 0ee2b8d702
commit f22de8150d
6 changed files with 254 additions and 179 deletions

View File

@@ -1,6 +1,6 @@
import axios from "axios"; import axios from "axios";
const API_URL = "https://hopp.zikor.pl"; const API_URL = "http://192.168.0.118:9000";
export async function listLocations() { export async function listLocations() {
try { try {
@@ -9,7 +9,6 @@ export async function listLocations() {
return "No locations found"; return "No locations found";
} }
// Нормализуем изображения в полученных данных
return response.data.map(location => ({ return response.data.map(location => ({
...location, ...location,
imageSource: normalizeImageSource(location.image) imageSource: normalizeImageSource(location.image)
@@ -23,23 +22,18 @@ export async function listLocations() {
const normalizeImageSource = (image) => { const normalizeImageSource = (image) => {
if (!image) return null; if (!image) return null;
// Проверка, является ли изображение URL
if (typeof image === 'string') { if (typeof image === 'string') {
// Если строка начинается с http или https, это URL
if (image.startsWith('http://') || image.startsWith('https://')) { if (image.startsWith('http://') || image.startsWith('https://')) {
return { uri: image }; return { uri: image };
} }
// Проверка на base64
if (image.startsWith('data:image')) { if (image.startsWith('data:image')) {
return { uri: image }; return { uri: image };
} else if (image.length > 100) { } else if (image.length > 100) {
// Предполагаем, что это base64 без префикса
return { uri: `data:image/jpeg;base64,${image}` }; return { uri: `data:image/jpeg;base64,${image}` };
} }
} }
// Возвращаем null для неправильного формата
return null; return null;
} }
@@ -47,7 +41,8 @@ export async function getLocation(id) {
try { try {
const location = await axios.get(`${API_URL}/locations/${id}`); const location = await axios.get(`${API_URL}/locations/${id}`);
if (!location) { 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)}]; return [...location.data, {image: normalizeImageSource(location.image)}];
@@ -65,7 +60,8 @@ export async function addLocation(location) {
}, },
}); });
if (!response) { if (!response) {
throw new Error("Failed to add location"); console.log("Error adding location");
return("Failed to add location");
} }
return response.data; return response.data;
} catch (error) { } catch (error) {
@@ -80,7 +76,8 @@ export async function updateLocation(id, location) {
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
}); });
if (!response) { if (!response) {
throw new Error("Failed to add location"); console.log("Failed to update location");
return("Failed to update location");
} }
return response.data; return response.data;
} catch (error) { } catch (error) {
@@ -93,7 +90,8 @@ export async function deleteLocation(id) {
try { try {
const response = await axios.delete(`${API_URL}/locations/${id}`); const response = await axios.delete(`${API_URL}/locations/${id}`);
if (!response) { if (!response) {
throw new Error("Failed to delete location"); console.log("Error deleting location");
return("Failed to delete location");
} }
return response.data; return response.data;
} catch (error) { } catch (error) {

View File

@@ -33,6 +33,12 @@
{ {
"photosPermission": "The app accesses your photos to let you share them with your friends." "photosPermission": "The app accesses your photos to let you share them with your friends."
} }
],
[
"expo-location",
{
"locationAlwaysAndWhenInUsePermission": "Allow $(PRODUCT_NAME) to use your location."
}
] ]
] ]
} }

View File

@@ -6,9 +6,11 @@ import {
ScrollView, ScrollView,
Image, Image,
View, View,
Alert,
} from "react-native"; } 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 {requestCameraPermissionsAsync, launchCameraAsync} from 'expo-image-picker';
import * as Location from 'expo-location';
import useLocationStore from "@/locationStore"; import useLocationStore from "@/locationStore";
export default function FormScreen() { export default function FormScreen() {
@@ -18,11 +20,15 @@ export default function FormScreen() {
image: "", image: "",
area: 0, area: 0,
population: 0, population: 0,
latitude: 0,
longitude: 0,
}); });
const [message, setMessage] = useState(""); const [message, setMessage] = useState("");
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [picture, setPicture] = useState(null); 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); const addLocation = useLocationStore((state) => state.addLocation);
@@ -32,7 +38,9 @@ export default function FormScreen() {
formData.description && formData.description &&
formData.image && formData.image &&
formData.area && formData.area &&
formData.population formData.population &&
formData.latitude &&
formData.longitude
) { ) {
const newLocation = { const newLocation = {
id: Date.now(), id: Date.now(),
@@ -41,6 +49,8 @@ export default function FormScreen() {
image: formData.image, image: formData.image,
area: parseFloat(formData.area), area: parseFloat(formData.area),
population: parseInt(formData.population), population: parseInt(formData.population),
latitude: parseFloat(formData.latitude),
longitude: parseFloat(formData.longitude),
}; };
const added = await addLocation(newLocation); const added = await addLocation(newLocation);
@@ -50,6 +60,8 @@ export default function FormScreen() {
image: "", image: "",
area: 0, area: 0,
population: 0, population: 0,
latitude: 0,
longitude: 0
}); });
setPicture(null); setPicture(null);
setImageMethod(null); setImageMethod(null);
@@ -83,11 +95,36 @@ export default function FormScreen() {
if (!result.canceled && result.assets && result.assets.length > 0) { if (!result.canceled && result.assets && result.assets.length > 0) {
const image = result.assets[0]; const image = result.assets[0];
setPicture(image.uri); setPicture(image.uri);
console.log(image.base64);
setFormData({...formData, image: 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) => { const selectImageMethod = (method) => {
setImageMethod(method); setImageMethod(method);
if (method === 'camera') { if (method === 'camera') {
@@ -103,7 +140,9 @@ export default function FormScreen() {
style={{flex: 1}} style={{flex: 1}}
behavior={Platform.OS === "ios" ? "padding" : "height"} behavior={Platform.OS === "ios" ? "padding" : "height"}
> >
<ScrollView contentContainerStyle={styles.container}> <ScrollView contentContainerStyle={styles.container} contentInsetAdjustmentBehavior="automatic"
style={[{backgroundColor: theme.colors.background}]}
>
<Snackbar <Snackbar
visible={visible} visible={visible}
onDismiss={() => setVisible(false)} onDismiss={() => setVisible(false)}
@@ -193,6 +232,14 @@ export default function FormScreen() {
> >
Dodaj Dodaj
</Button> </Button>
<Button
style={{margin: 10, width: "100%"}} mode={"contained"}
onPress={getCurrentLocation}
icon={location ? "check-circle-outline" : "map-marker-outline"}
>
Pobierz aktualną lokalizację
</Button>
</ScrollView> </ScrollView>
</KeyboardAvoidingView> </KeyboardAvoidingView>
); );
@@ -200,11 +247,10 @@ export default function FormScreen() {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, // backgroundColor: "#25292e",
backgroundColor: "#25292e",
justifyContent: "flex-start",
alignItems: "center", alignItems: "center",
padding: 10, padding: 10,
flexGrow: 1,
}, },
imageContainer: { imageContainer: {
width: "100%", width: "100%",
@@ -215,7 +261,6 @@ const styles = StyleSheet.create({
width: 150, width: 150,
height: 150, height: 150,
borderStyle: "solid", borderStyle: "solid",
borderColor: "#fff",
borderWidth: 1, borderWidth: 1,
borderRadius: 5, borderRadius: 5,
}, },
@@ -232,7 +277,6 @@ const styles = StyleSheet.create({
label: { label: {
marginTop: 10, marginTop: 10,
marginBottom: 10, marginBottom: 10,
color: "#fff",
verticalAlign: "middle", verticalAlign: "middle",
textAlign: "center", textAlign: "center",
} }

View File

@@ -28,7 +28,7 @@ export default function Location() {
} }
return ( return (
<View style={styles.container}> <View style={[styles.container, {backgroundColor: theme.colors.background}]}>
<ScrollView> <ScrollView>
<Card style={{ margin: 10 }}> <Card style={{ margin: 10 }}>
<Card.Cover <Card.Cover
@@ -55,6 +55,9 @@ export default function Location() {
<Text variant="bodyMedium" style={{ marginBottom: 10 }}> <Text variant="bodyMedium" style={{ marginBottom: 10 }}>
Ludność: {location.population} osób Ludność: {location.population} osób
</Text> </Text>
<Text variant="bodyMedium" style={{ marginBottom: 10 }}>
Współrzedne geograficzne: {location.latitude}, {location.longitude}
</Text>
</Card.Content> </Card.Content>
</Card> </Card>
</ScrollView> </ScrollView>
@@ -67,7 +70,6 @@ const styles = StyleSheet.create({
flex: 1, flex: 1,
backgroundColor: "#25292e", backgroundColor: "#25292e",
justifyContent: "center", justifyContent: "center",
alignItems: "center",
}, },
text: { text: {
color: "#fff", color: "#fff",

View File

@@ -22,6 +22,8 @@ export default function EditLocation() {
image: "", image: "",
area: "", area: "",
population: "", population: "",
longitude: "",
latitude: "",
}); });
const [message, setMessage] = useState(""); const [message, setMessage] = useState("");
@@ -39,6 +41,8 @@ export default function EditLocation() {
image: data.image, image: data.image,
area: data.area.toString(), area: data.area.toString(),
population: data.population.toString(), population: data.population.toString(),
longitude: data.longitude.toString(),
latitude: data.latitude.toString(),
}); });
} }
setLoading(false); setLoading(false);
@@ -50,7 +54,9 @@ export default function EditLocation() {
formData.description && formData.description &&
formData.image && formData.image &&
formData.area && formData.area &&
formData.population formData.population &&
formData.longitude &&
formData.latitude
) { ) {
// console.log("Form data:", formData); // console.log("Form data:", formData);
const response = await updateLocation(id, { const response = await updateLocation(id, {
@@ -148,6 +154,24 @@ export default function EditLocation() {
keyboardType="numeric" keyboardType="numeric"
onChangeText={(e) => setFormData({...formData, population: e})} onChangeText={(e) => setFormData({...formData, population: e})}
/> />
<TextInput
mode="outlined"
label="Długość geograficzna"
placeholder="Wpisz długość geograficzną"
style={{margin: 10, width: "100%"}}
value={formData.longitude}
keyboardType="numeric"
onChangeText={(e) => setFormData({...formData, longitude: e})}
/>
<TextInput
mode="outlined"
label="Szerokość geograficzna"
placeholder="Wpisz szerokość geograficzną"
style={{margin: 10, width: "100%"}}
value={formData.latitude}
keyboardType="numeric"
onChangeText={(e) => setFormData({...formData, latitude: e})}
/>
<Button <Button
style={{margin: 10, width: "100%"}} style={{margin: 10, width: "100%"}}
icon="plus-circle-outline" icon="plus-circle-outline"

View File

@@ -18,6 +18,7 @@
"expo-router": "~5.0.7", "expo-router": "~5.0.7",
"expo-status-bar": "~2.2.3", "expo-status-bar": "~2.2.3",
"expo-image-picker": "~16.1.4", "expo-image-picker": "~16.1.4",
"expo-location": "~18.1.5",
"react": "19.0.0", "react": "19.0.0",
"react-dom": "19.0.0", "react-dom": "19.0.0",
"react-native": "0.79.2", "react-native": "0.79.2",