support for resume on multiple devices, fix camera freeze bug when opening setup overlay
All checks were successful
pedestrian-simulator / build (push) Successful in 1m19s
All checks were successful
pedestrian-simulator / build (push) Successful in 1m19s
This commit is contained in:
@@ -824,6 +824,11 @@ function showSetupOverlay() {
|
||||
|
||||
function hideSetupOverlay() {
|
||||
document.getElementById('setup-overlay').classList.remove('active');
|
||||
|
||||
// Resume animation if a trip is active
|
||||
if (localStorage.getItem(LOCATION_STORAGE)) {
|
||||
startCameraAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
function setupEventListeners() {
|
||||
@@ -989,6 +994,8 @@ async function calculateAndStartRoute(startAddress, endAddress, isRestoring = fa
|
||||
// Reset display steps for visual consistency
|
||||
displayTripSteps = 0;
|
||||
stateBuffer = [];
|
||||
window.lastPositionUpdateDistance = 0;
|
||||
window.lastPanoUpdate = 0;
|
||||
|
||||
startFromLocation(leg.start_location, locationData.startAddress);
|
||||
hideSetupOverlay();
|
||||
@@ -1169,7 +1176,7 @@ function resetLocation() {
|
||||
showSetupOverlay();
|
||||
document.getElementById('startLocationInput').value = '';
|
||||
document.getElementById('endLocationInput').value = '';
|
||||
stopAnimation();
|
||||
// stopAnimation(); // Don't stop animation just because we opened the setup overlay
|
||||
}
|
||||
|
||||
// Rate limiting for refresh
|
||||
@@ -1230,9 +1237,42 @@ async function fetchStatus() {
|
||||
const data = await response.json();
|
||||
const now = Date.now();
|
||||
|
||||
// Server-Side Trip Synchronization
|
||||
if (data.activeTrip) {
|
||||
// A trip is active on the server
|
||||
|
||||
// Check if we need to sync/resume this trip locally
|
||||
const localLocation = localStorage.getItem(LOCATION_STORAGE);
|
||||
let needsResync = false;
|
||||
|
||||
if (!localLocation) {
|
||||
needsResync = true;
|
||||
console.log("[Sync] No local trip found. Syncing from server.");
|
||||
} else {
|
||||
// We have a local trip, check if it's the SAME trip
|
||||
try {
|
||||
const localData = JSON.parse(localLocation);
|
||||
if (localData.routeName !== data.activeTrip.route_name) {
|
||||
needsResync = true;
|
||||
console.log("[Sync] Local trip route mismatch. Syncing from server.");
|
||||
}
|
||||
} catch (e) {
|
||||
needsResync = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsResync) {
|
||||
syncActiveTrip(data.activeTrip);
|
||||
}
|
||||
|
||||
// Update target steps from server
|
||||
if (data.tripSteps !== undefined) {
|
||||
// Add to buffer
|
||||
// Safety: Only accept step updates if they are for the current trip
|
||||
if (needsResync) {
|
||||
stateBuffer = [];
|
||||
displayTripSteps = 0;
|
||||
}
|
||||
|
||||
stateBuffer.push({ t: now, s: data.tripSteps });
|
||||
|
||||
// Keep buffer size manageable (20 points is ~1.5 mins)
|
||||
@@ -1240,6 +1280,23 @@ async function fetchStatus() {
|
||||
stateBuffer.shift();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No trip active on the server
|
||||
if (localStorage.getItem(LOCATION_STORAGE)) {
|
||||
console.log("[Sync] No trip on server. Clearing local trip.");
|
||||
localStorage.removeItem(LOCATION_STORAGE);
|
||||
|
||||
if (!document.getElementById('celebration-overlay').classList.contains('active')) {
|
||||
document.getElementById('routeInfo').textContent = 'Not Started';
|
||||
document.getElementById('currentSteps').textContent = '0';
|
||||
document.getElementById('tripMeter').textContent = '0.0 / 0.0 km';
|
||||
masterPath = [];
|
||||
routeTotalDistance = 0;
|
||||
displayTripSteps = 0;
|
||||
stateBuffer = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update user info
|
||||
updateUserProfile(data.user);
|
||||
@@ -1254,6 +1311,24 @@ async function fetchStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
async function syncActiveTrip(activeTrip) {
|
||||
console.log("[Sync] Restoring trip from server:", activeTrip.route_name);
|
||||
|
||||
if (activeTrip.trip_type === 'address') {
|
||||
calculateAndStartRoute(activeTrip.start_address, activeTrip.end_address, true);
|
||||
} else if (activeTrip.trip_type === 'kml') {
|
||||
try {
|
||||
const response = await fetch(`/api/kml/download?owner_id=${activeTrip.kml_owner_id || currentUserID}&filename=${encodeURIComponent(activeTrip.route_name)}`);
|
||||
if (response.ok) {
|
||||
const kmlContent = await response.text();
|
||||
processKML(kmlContent, activeTrip.route_name);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("[Sync] Failed to download KML for sync:", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateNextSyncCountdown(nextSyncTime) {
|
||||
const now = new Date();
|
||||
const diff = nextSyncTime - now;
|
||||
@@ -2154,6 +2229,8 @@ function startFromCustomRoute(pathData, routeName, isRestoring = false, markers
|
||||
// Reset display steps
|
||||
displayTripSteps = 0;
|
||||
stateBuffer = [];
|
||||
window.lastPositionUpdateDistance = 0;
|
||||
window.lastPanoUpdate = 0;
|
||||
|
||||
// Initialize Map View
|
||||
startFromLocation(startPoint, routeName);
|
||||
@@ -2301,6 +2378,14 @@ async function triggerCelebration(finalDistance) {
|
||||
currentTripDetails = null;
|
||||
masterPath = [];
|
||||
routeTotalDistance = 0;
|
||||
displayTripSteps = 0;
|
||||
stateBuffer = [];
|
||||
|
||||
// Update UI to reflect reset
|
||||
document.getElementById('routeInfo').textContent = 'Not Started';
|
||||
document.getElementById('currentSteps').textContent = '0';
|
||||
document.getElementById('tripMeter').textContent = '0.0 / 0.0 km';
|
||||
|
||||
// We keep window.hasCelebrated = true to prevent immediate re-trigger
|
||||
// but starting a new trip will reset it.
|
||||
}
|
||||
|
||||
@@ -360,10 +360,26 @@ func (sm *StepManager) GetStatus() map[string]interface{} {
|
||||
go sm.Sync() // Async sync
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
res := map[string]interface{}{
|
||||
"tripSteps": currentSmoothed,
|
||||
"nextSyncTime": nextSyncMilli,
|
||||
}
|
||||
|
||||
sm.mu.Lock()
|
||||
if sm.tripState.StartDate != "" {
|
||||
res["activeTrip"] = map[string]interface{}{
|
||||
"trip_type": sm.tripState.TripType,
|
||||
"route_name": sm.tripState.RouteName,
|
||||
"start_address": sm.tripState.StartAddress,
|
||||
"end_address": sm.tripState.EndAddress,
|
||||
"kml_id": sm.tripState.KmlID,
|
||||
"total_distance": sm.tripState.TotalDistance,
|
||||
"start_time": sm.tripState.StartTime,
|
||||
}
|
||||
}
|
||||
sm.mu.Unlock()
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// RecalculateTotalFromState sums up the steps from the DailyCache without making external API calls
|
||||
|
||||
Reference in New Issue
Block a user