Load all saved place into memory
Fixes launching the app with a place URL directly, and will be useful for search etc. later.
This commit is contained in:
parent
86b85e9a0b
commit
6e87ef3573
@ -407,8 +407,8 @@ export default class MapComponent extends Component {
|
||||
|
||||
// Re-fetch bookmarks when the version changes (triggered by parent action or service)
|
||||
updateBookmarks = modifier(() => {
|
||||
// Depend on the tracked storage.savedPlaces to automatically update when they change
|
||||
const places = this.storage.savedPlaces;
|
||||
// Depend on the tracked storage.placesInView to automatically update when they change
|
||||
const places = this.storage.placesInView;
|
||||
this.loadBookmarks(places);
|
||||
});
|
||||
|
||||
@ -418,13 +418,13 @@ export default class MapComponent extends Component {
|
||||
|
||||
if (!places || places.length === 0) {
|
||||
// Fallback or explicit check if we have tracked property usage?
|
||||
// The service updates 'savedPlaces'. We should probably use that if we want reactiveness.
|
||||
places = this.storage.savedPlaces;
|
||||
// The service updates 'placesInView'. We should probably use that if we want reactiveness.
|
||||
places = this.storage.placesInView;
|
||||
}
|
||||
|
||||
// Previously: const places = await this.storage.places.getPlaces();
|
||||
// We no longer want to fetch everything blindly.
|
||||
// We rely on 'savedPlaces' being updated by handleMapMove calling storage.loadPlacesInBounds.
|
||||
// We rely on 'placesInView' being updated by handleMapMove calling storage.loadPlacesInBounds.
|
||||
|
||||
this.bookmarkSource.clear();
|
||||
|
||||
@ -457,7 +457,7 @@ export default class MapComponent extends Component {
|
||||
|
||||
const bbox = { minLat, minLon, maxLat, maxLon };
|
||||
await this.storage.loadPlacesInBounds(bbox);
|
||||
this.loadBookmarks(this.storage.savedPlaces);
|
||||
this.loadBookmarks(this.storage.placesInView);
|
||||
|
||||
// Persist view to localStorage
|
||||
try {
|
||||
|
||||
@ -16,6 +16,9 @@ export default class PlaceRoute extends Route {
|
||||
return this.loadOsmPlace(osmId, type);
|
||||
}
|
||||
|
||||
// Wait for storage sync before checking bookmarks
|
||||
await this.waitForSync();
|
||||
|
||||
// 1. Try to find in local bookmarks
|
||||
let bookmark = this.storage.findPlaceById(id);
|
||||
|
||||
@ -29,6 +32,22 @@ export default class PlaceRoute extends Route {
|
||||
return this.loadOsmPlace(id);
|
||||
}
|
||||
|
||||
async waitForSync() {
|
||||
if (this.storage.initialSyncDone) return;
|
||||
|
||||
console.log('Waiting for initial storage sync...');
|
||||
const timeout = 5000;
|
||||
const start = Date.now();
|
||||
|
||||
while (!this.storage.initialSyncDone) {
|
||||
if (Date.now() - start > timeout) {
|
||||
console.warn('Timed out waiting for initial sync');
|
||||
break;
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
}
|
||||
|
||||
afterModel(model) {
|
||||
// Notify the Map UI to show the pin
|
||||
if (model) {
|
||||
|
||||
@ -8,6 +8,7 @@ import Geohash from 'latlon-geohash';
|
||||
|
||||
export default class StorageService extends Service {
|
||||
rs;
|
||||
@tracked placesInView = [];
|
||||
@tracked savedPlaces = [];
|
||||
@tracked loadedPrefixes = [];
|
||||
@tracked currentBbox = null;
|
||||
@ -35,17 +36,60 @@ export default class StorageService extends Service {
|
||||
// console.debug('[rs] client ready');
|
||||
});
|
||||
|
||||
this.rs.on('sync-done', result => {
|
||||
this.rs.on('sync-done', (result) => {
|
||||
// console.debug('[rs] sync done:', result);
|
||||
if (!this.initialSyncDone) { this.initialSyncDone = true; }
|
||||
if (!this.initialSyncDone) {
|
||||
this.initialSyncDone = true;
|
||||
}
|
||||
});
|
||||
|
||||
this.rs.scope('/places/').on('change', (event) => {
|
||||
console.debug(event);
|
||||
// console.debug(event);
|
||||
this.handlePlaceChange(event);
|
||||
debounce(this, this.reloadCurrentView, 200);
|
||||
});
|
||||
}
|
||||
|
||||
handlePlaceChange(event) {
|
||||
const { newValue, relativePath } = event;
|
||||
|
||||
// Remove old entry if exists
|
||||
// The relativePath is like "geohash/geohash/ULID" or just "ULID" depending on structure.
|
||||
// Our structure is <2-char>/<2-char>/<id>.
|
||||
// But let's rely on the ID inside the object if possible, or extract from path.
|
||||
|
||||
// We can't easily identify the ID from just relativePath without parsing logic if it's nested.
|
||||
// However, for deletions (newValue is undefined), we might need the ID.
|
||||
// Fortunately, our objects (newValue) contain the ID.
|
||||
|
||||
// If it's a deletion, we need to find the object in our array to remove it.
|
||||
// Since we don't have the ID in newValue (it's null), we rely on `relativePath`.
|
||||
// Let's assume the filename is the ID.
|
||||
const pathParts = relativePath.split('/');
|
||||
const id = pathParts[pathParts.length - 1];
|
||||
|
||||
if (!newValue) {
|
||||
// Deletion
|
||||
this.savedPlaces = this.savedPlaces.filter((p) => p.id !== id);
|
||||
} else {
|
||||
// Add or Update
|
||||
// Ensure the object has the ID (it should)
|
||||
const place = { ...newValue, id };
|
||||
|
||||
// Update existing or add new
|
||||
const index = this.savedPlaces.findIndex((p) => p.id === id);
|
||||
if (index !== -1) {
|
||||
// Replace
|
||||
const newPlaces = [...this.savedPlaces];
|
||||
newPlaces[index] = place;
|
||||
this.savedPlaces = newPlaces;
|
||||
} else {
|
||||
// Add
|
||||
this.savedPlaces = [...this.savedPlaces, place];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get places() {
|
||||
return this.rs.places;
|
||||
}
|
||||
@ -105,7 +149,7 @@ export default class StorageService extends Service {
|
||||
// Identify existing places that belong to the reloaded prefixes and remove them
|
||||
const prefixSet = new Set(prefixes);
|
||||
|
||||
const keptPlaces = this.savedPlaces.filter((place) => {
|
||||
const keptPlaces = this.placesInView.filter((place) => {
|
||||
if (!place.lat || !place.lon) return false;
|
||||
try {
|
||||
// Calculate 4-char geohash for the existing place
|
||||
@ -119,15 +163,15 @@ export default class StorageService extends Service {
|
||||
});
|
||||
|
||||
// Merge the kept places (from other areas) with the fresh places (from these areas)
|
||||
this.savedPlaces = [...keptPlaces, ...places];
|
||||
this.placesInView = [...keptPlaces, ...places];
|
||||
} else {
|
||||
// Full reload
|
||||
this.savedPlaces = places;
|
||||
this.placesInView = places;
|
||||
}
|
||||
} else {
|
||||
if (!prefixes) this.savedPlaces = [];
|
||||
if (!prefixes) this.placesInView = [];
|
||||
}
|
||||
console.log('Loaded saved places:', this.savedPlaces.length);
|
||||
console.log('Loaded saved places:', this.placesInView.length);
|
||||
} catch (e) {
|
||||
console.error('Failed to load places:', e);
|
||||
}
|
||||
|
||||
11
tests/unit/routes/place-test.js
Normal file
11
tests/unit/routes/place-test.js
Normal file
@ -0,0 +1,11 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'marco/tests/helpers';
|
||||
|
||||
module('Unit | Route | place', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let route = this.owner.lookup('route:place');
|
||||
assert.ok(route);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user