import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {ActivityIndicator, StyleSheet, Text, View} from 'react-native';
import * as Location from 'expo-location';
import {Magnetometer} from 'expo-sensors';
import Screen from '../layout/Screen';
import PlayerMapView from '../gameplay/PlayerMapView';
import useGameHook from '../../hooks/useGameHook';
import usePlayerGame from '../../hooks/usePlayerGame';
import {getSession} from '../../hooks/SessionStore';
import Cache from '../../models/Cache';
const toHeading = ({ x, y }) => {
const angle = Math.atan2(y, x) * (180 / Math.PI);
return angle < 0 ? angle + 360 : angle;
};
const MapScreen = () => {
const session = getSession();
const { getCaches, claimCache } = useGameHook();
const [userLocation, setUserLocation] = useState(null);
const [heading, setHeading] = useState(null);
const [loading, setLoading] = useState(true);
const [cacheRecords, setCacheRecords] = useState([]);
const [error, setError] = useState('');
const activeCaches = useMemo(() => (
cacheRecords.map(
(cache) => new Cache(
cache.id,
cache.coordinates.latitude,
cache.coordinates.longitude,
cache.radius,
cache.clue,
cache.groupId,
cache.subgroupId,
),
)
), [cacheRecords]);
const subgroupFilter = session.currentSGid;
const { visibleCache, isClaiming, setIsClaiming } = usePlayerGame(userLocation, heading, activeCaches);
const loadCaches = useCallback(() => {
if (!session.currentGid) {
setCacheRecords([]);
return;
}
const rows = getCaches(session.currentGid, subgroupFilter);
setCacheRecords(rows);
}, [getCaches, session.currentGid, subgroupFilter]);
useEffect(() => {
loadCaches();
}, [loadCaches]);
useEffect(() => {
let locationSub;
let headingSub;
const start = async () => {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
setError('Location permission denied');
setLoading(false);
return;
}
const current = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.Balanced });
setUserLocation({ latitude: current.coords.latitude, longitude: current.coords.longitude });
locationSub = await Location.watchPositionAsync(
{
accuracy: Location.Accuracy.Balanced,
distanceInterval: 1,
timeInterval: 1000,
},
(next) => {
setUserLocation({ latitude: next.coords.latitude, longitude: next.coords.longitude });
},
);
Magnetometer.setUpdateInterval(500);
headingSub = Magnetometer.addListener((data) => {
setHeading(toHeading(data));
});
setLoading(false);
};
start();
return () => {
if (locationSub) {
locationSub.remove();
}
if (headingSub) {
headingSub.remove();
}
};
}, []);
const handleClaim = (cacheId) => {
if (!session.currentGid) {
return;
}
claimCache({
gid: session.currentGid,
cacheId,
uid: session.currentUid,
tid: session.currentTid,
});
setIsClaiming(false);
loadCaches();
};
if (!session.currentGid) {
return (
Join or create a game to use map features.
);
}
if (session.isAcceptedAdmin) {
return (
Admins manage caches from Manage Game.
);
}
if (loading) {
return (
);
}
if (error) {
return (
{error}
);
}
return (
);
};
const styles = StyleSheet.create({
container: {
padding: 0,
},
mapWrap: {
flex: 1,
},
center: {
justifyContent: 'center',
alignItems: 'center',
},
body: {
color: '#4b5563',
fontSize: 15,
},
error: {
color: '#dc2626',
fontSize: 15,
},
});
export default MapScreen;