mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-31 15:43:25 +00:00
finish reworking immer updates
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { ramerDouglasPeucker } from "./simplify";
|
import { ramerDouglasPeucker } from "./simplify";
|
||||||
import { Coordinates, GPXFileAttributes, GPXFileType, LineStyleExtension, Link, Metadata, TrackExtensions, TrackPointExtensions, TrackPointType, TrackSegmentType, TrackType, WaypointType } from "./types";
|
import { Coordinates, GPXFileAttributes, GPXFileType, LineStyleExtension, Link, Metadata, TrackExtensions, TrackPointExtensions, TrackPointType, TrackSegmentType, TrackType, WaypointType } from "./types";
|
||||||
import { Draft, immerable, isDraft, original, produce, freeze } from "immer";
|
import { immerable, isDraft, original, freeze } from "immer";
|
||||||
|
|
||||||
function cloneJSON<T>(obj: T): T {
|
function cloneJSON<T>(obj: T): T {
|
||||||
if (obj === null || typeof obj !== 'object') {
|
if (obj === null || typeof obj !== 'object') {
|
||||||
@@ -209,23 +209,23 @@ export class GPXFile extends GPXTreeNode<Track>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Producers
|
// Producers
|
||||||
replaceTracks(start: number, end: number, tracks: Track[]): Track[] {
|
replaceTracks(start: number, end: number, tracks: Track[]) {
|
||||||
if (this._data.style) {
|
if (this._data.style) {
|
||||||
tracks.forEach((track) => track.setStyle(this._data.style, false));
|
tracks.forEach((track) => track.setStyle(this._data.style, false));
|
||||||
}
|
}
|
||||||
return this.trk.splice(start, end - start + 1, ...tracks);
|
this.trk.splice(start, end - start + 1, ...tracks);
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceTrackSegments(trackIndex: number, start: number, end: number, segments: TrackSegment[]): TrackSegment[] {
|
replaceTrackSegments(trackIndex: number, start: number, end: number, segments: TrackSegment[]) {
|
||||||
return this.trk[trackIndex].replaceTrackSegments(start, end, segments);
|
this.trk[trackIndex].replaceTrackSegments(start, end, segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceTrackPoints(trackIndex: number, segmentIndex: number, start: number, end: number, points: TrackPoint[], speed?: number, startTime?: Date) {
|
replaceTrackPoints(trackIndex: number, segmentIndex: number, start: number, end: number, points: TrackPoint[], speed?: number, startTime?: Date) {
|
||||||
this.trk[trackIndex].replaceTrackPoints(segmentIndex, start, end, points, speed, startTime);
|
this.trk[trackIndex].replaceTrackPoints(segmentIndex, start, end, points, speed, startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceWaypoints(start: number, end: number, waypoints: Waypoint[]): Waypoint[] {
|
replaceWaypoints(start: number, end: number, waypoints: Waypoint[]) {
|
||||||
return this.wpt.splice(start, end - start + 1, ...waypoints);
|
this.wpt.splice(start, end - start + 1, ...waypoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
reverse() {
|
reverse() {
|
||||||
@@ -347,28 +347,22 @@ export class GPXFile extends GPXTreeNode<Track>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
setHiddenWaypoints(hidden: boolean, waypointIndices?: number[]) {
|
setHiddenWaypoints(hidden: boolean, waypointIndices?: number[]) {
|
||||||
return produce(this, (draft) => {
|
let allHiddenWpt = hidden;
|
||||||
let og = getOriginal(draft); // Read as much as possible from the original object because it is faster
|
this.wpt.forEach((waypoint, index) => {
|
||||||
|
if (waypointIndices === undefined || waypointIndices.includes(index)) {
|
||||||
let allHiddenWpt = hidden;
|
waypoint.setHidden(hidden);
|
||||||
let wpt = og.wpt.map((waypoint, index) => {
|
} else {
|
||||||
if (waypointIndices === undefined || waypointIndices.includes(index)) {
|
allHiddenWpt = allHiddenWpt && (waypoint._data.hidden === true);
|
||||||
return waypoint.setHidden(hidden);
|
}
|
||||||
} else {
|
|
||||||
allHiddenWpt = allHiddenWpt && (waypoint._data.hidden === true);
|
|
||||||
return waypoint;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
draft.wpt = freeze(wpt); // Pre-freeze the array, faster as well
|
|
||||||
|
|
||||||
let allHiddenTrk = true;
|
|
||||||
og.trk.forEach((track) => {
|
|
||||||
allHiddenTrk = allHiddenTrk && (track._data.hidden === true);
|
|
||||||
});
|
|
||||||
|
|
||||||
draft._data.hiddenWpt = allHiddenWpt;
|
|
||||||
draft._data.hidden = allHiddenTrk && allHiddenWpt;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let allHiddenTrk = true;
|
||||||
|
this.trk.forEach((track) => {
|
||||||
|
allHiddenTrk = allHiddenTrk && (track._data.hidden === true);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._data.hiddenWpt = allHiddenWpt;
|
||||||
|
this._data.hidden = allHiddenTrk && allHiddenWpt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -458,8 +452,8 @@ export class Track extends GPXTreeNode<TrackSegment> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Producers
|
// Producers
|
||||||
replaceTrackSegments(start: number, end: number, segments: TrackSegment[]): TrackSegment[] {
|
replaceTrackSegments(start: number, end: number, segments: TrackSegment[]) {
|
||||||
return this.trkseg.splice(start, end - start + 1, ...segments);
|
this.trkseg.splice(start, end - start + 1, ...segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceTrackPoints(segmentIndex: number, start: number, end: number, points: TrackPoint[], speed?: number, startTime?: Date) {
|
replaceTrackPoints(segmentIndex: number, start: number, end: number, points: TrackPoint[], speed?: number, startTime?: Date) {
|
||||||
@@ -494,23 +488,21 @@ export class Track extends GPXTreeNode<TrackSegment> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clean(bounds: [Coordinates, Coordinates], inside: boolean, segmentIndices?: number[]) {
|
clean(bounds: [Coordinates, Coordinates], inside: boolean, segmentIndices?: number[]) {
|
||||||
return produce(this, (draft) => {
|
let i = 0;
|
||||||
let i = 0;
|
let segmentIndex = 0;
|
||||||
let segmentIndex = 0;
|
while (i < this.trkseg.length) {
|
||||||
while (i < this.trkseg.length) {
|
if (segmentIndices === undefined || segmentIndices.includes(segmentIndex)) {
|
||||||
if (segmentIndices === undefined || segmentIndices.includes(segmentIndex)) {
|
this.trkseg[i].clean(bounds, inside);
|
||||||
this.trkseg[i].clean(bounds, inside);
|
if (this.trkseg[i].getNumberOfTrackPoints() === 0) {
|
||||||
if (this.trkseg[i].getNumberOfTrackPoints() === 0) {
|
this.trkseg.splice(i, 1);
|
||||||
this.trkseg.splice(i, 1);
|
|
||||||
} else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
segmentIndex++;
|
} else {
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
});
|
segmentIndex++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeTimestamps(startTime: Date, speed: number, ratio: number, lastPoint?: TrackPoint, segmentIndex?: number) {
|
changeTimestamps(startTime: Date, speed: number, ratio: number, lastPoint?: TrackPoint, segmentIndex?: number) {
|
||||||
|
@@ -327,27 +327,29 @@ export function moveItems(fromParent: ListItem, toParent: ListItem, fromItems: L
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sortItems(fromItems, remove && !(fromParent instanceof ListRootItem));
|
sortItems(fromItems, false);
|
||||||
sortItems(toItems, false);
|
sortItems(toItems, false);
|
||||||
|
|
||||||
let context: (GPXFile | Track | TrackSegment | Waypoint[] | Waypoint)[] = [];
|
let context: (GPXFile | Track | TrackSegment | Waypoint[] | Waypoint)[] = [];
|
||||||
if (!remove || fromParent instanceof ListRootItem) {
|
fromItems.forEach((item) => {
|
||||||
fromItems.forEach((item) => {
|
let file = getFile(item.getFileId());
|
||||||
let file = getFile(item.getFileId());
|
if (file) {
|
||||||
if (file) {
|
if (item instanceof ListFileItem) {
|
||||||
if (item instanceof ListFileItem) {
|
context.push(file.clone());
|
||||||
context.push(file.clone());
|
} else if (item instanceof ListTrackItem && item.getTrackIndex() < file.trk.length) {
|
||||||
} else if (item instanceof ListTrackItem && item.getTrackIndex() < file.trk.length) {
|
context.push(file.trk[item.getTrackIndex()].clone());
|
||||||
context.push(file.trk[item.getTrackIndex()].clone());
|
} else if (item instanceof ListTrackSegmentItem && item.getTrackIndex() < file.trk.length && item.getSegmentIndex() < file.trk[item.getTrackIndex()].trkseg.length) {
|
||||||
} else if (item instanceof ListTrackSegmentItem && item.getTrackIndex() < file.trk.length && item.getSegmentIndex() < file.trk[item.getTrackIndex()].trkseg.length) {
|
context.push(file.trk[item.getTrackIndex()].trkseg[item.getSegmentIndex()].clone());
|
||||||
context.push(file.trk[item.getTrackIndex()].trkseg[item.getSegmentIndex()].clone());
|
} else if (item instanceof ListWaypointsItem) {
|
||||||
} else if (item instanceof ListWaypointsItem) {
|
context.push(file.wpt.map((wpt) => wpt.clone()));
|
||||||
context.push(file.wpt.map((wpt) => wpt.clone()));
|
} else if (item instanceof ListWaypointItem && item.getWaypointIndex() < file.wpt.length) {
|
||||||
} else if (item instanceof ListWaypointItem && item.getWaypointIndex() < file.wpt.length) {
|
context.push(file.wpt[item.getWaypointIndex()].clone());
|
||||||
context.push(file.wpt[item.getWaypointIndex()].clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (remove && !(fromParent instanceof ListRootItem)) {
|
||||||
|
sortItems(fromItems, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let files = [fromParent.getFileId(), toParent.getFileId()];
|
let files = [fromParent.getFileId(), toParent.getFileId()];
|
||||||
@@ -355,16 +357,15 @@ export function moveItems(fromParent: ListItem, toParent: ListItem, fromItems: L
|
|||||||
(file, context: (GPXFile | Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
|
(file, context: (GPXFile | Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
|
||||||
fromItems.forEach((item) => {
|
fromItems.forEach((item) => {
|
||||||
if (item instanceof ListTrackItem) {
|
if (item instanceof ListTrackItem) {
|
||||||
context.push(...file.replaceTracks(item.getTrackIndex(), item.getTrackIndex(), []));
|
file.replaceTracks(item.getTrackIndex(), item.getTrackIndex(), []);
|
||||||
} else if (item instanceof ListTrackSegmentItem) {
|
} else if (item instanceof ListTrackSegmentItem) {
|
||||||
context.push(...file.replaceTrackSegments(item.getTrackIndex(), item.getSegmentIndex(), item.getSegmentIndex(), []));
|
file.replaceTrackSegments(item.getTrackIndex(), item.getSegmentIndex(), item.getSegmentIndex(), []);
|
||||||
} else if (item instanceof ListWaypointsItem) {
|
} else if (item instanceof ListWaypointsItem) {
|
||||||
context.push(file.replaceWaypoints(0, newFile.wpt.length - 1, []));
|
file.replaceWaypoints(0, file.wpt.length - 1, []);
|
||||||
} else if (item instanceof ListWaypointItem) {
|
} else if (item instanceof ListWaypointItem) {
|
||||||
context.push(...file.replaceWaypoints(item.getWaypointIndex(), item.getWaypointIndex(), []));
|
file.replaceWaypoints(item.getWaypointIndex(), item.getWaypointIndex(), []);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
context.reverse();
|
|
||||||
},
|
},
|
||||||
(file, context: (GPXFile | Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
|
(file, context: (GPXFile | Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
|
||||||
toItems.forEach((item, i) => {
|
toItems.forEach((item, i) => {
|
||||||
@@ -415,15 +416,14 @@ export function moveItems(fromParent: ListItem, toParent: ListItem, fromItems: L
|
|||||||
if (context[i].name) {
|
if (context[i].name) {
|
||||||
newFile.metadata.name = context[i].name;
|
newFile.metadata.name = context[i].name;
|
||||||
}
|
}
|
||||||
console.log(context[i]);
|
newFile.replaceTracks(0, 0, [context[i]]);
|
||||||
newFile.replaceTracks(0, 0, [context[i]])[0];
|
|
||||||
files.set(item.getFileId(), freeze(newFile));
|
files.set(item.getFileId(), freeze(newFile));
|
||||||
} else if (context[i] instanceof TrackSegment) {
|
} else if (context[i] instanceof TrackSegment) {
|
||||||
let newFile = newGPXFile();
|
let newFile = newGPXFile();
|
||||||
newFile._data.id = item.getFileId();
|
newFile._data.id = item.getFileId();
|
||||||
newFile.replaceTracks(0, 0, [new Track({
|
newFile.replaceTracks(0, 0, [new Track({
|
||||||
trkseg: [context[i]]
|
trkseg: [context[i]]
|
||||||
})])[0];
|
})]);
|
||||||
files.set(item.getFileId(), freeze(newFile));
|
files.set(item.getFileId(), freeze(newFile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -190,8 +190,9 @@
|
|||||||
if (Sortable.get(e.from)._waypointRoot) {
|
if (Sortable.get(e.from)._waypointRoot) {
|
||||||
fromItems = [fromItem.extend('waypoints')];
|
fromItems = [fromItem.extend('waypoints')];
|
||||||
} else {
|
} else {
|
||||||
let oldIndices =
|
let oldIndices: number[] =
|
||||||
e.oldIndicies.length > 0 ? e.oldIndicies.map((i) => i.index) : [e.oldIndex];
|
e.oldIndicies.length > 0 ? e.oldIndicies.map((i) => i.index) : [e.oldIndex];
|
||||||
|
oldIndices = oldIndices.filter((i) => i >= 0);
|
||||||
oldIndices.sort((a, b) => a - b);
|
oldIndices.sort((a, b) => a - b);
|
||||||
|
|
||||||
fromItems = oldIndices.map((i) => fromItem.extend(i));
|
fromItems = oldIndices.map((i) => fromItem.extend(i));
|
||||||
@@ -204,8 +205,9 @@
|
|||||||
toItem = toItem.extend('waypoints');
|
toItem = toItem.extend('waypoints');
|
||||||
}
|
}
|
||||||
|
|
||||||
let newIndices =
|
let newIndices: number[] =
|
||||||
e.newIndicies.length > 0 ? e.newIndicies.map((i) => i.index) : [e.newIndex];
|
e.newIndicies.length > 0 ? e.newIndicies.map((i) => i.index) : [e.newIndex];
|
||||||
|
newIndices = newIndices.filter((i) => i >= 0);
|
||||||
newIndices.sort((a, b) => a - b);
|
newIndices.sort((a, b) => a - b);
|
||||||
|
|
||||||
if (toItem instanceof ListRootItem) {
|
if (toItem instanceof ListRootItem) {
|
||||||
|
@@ -103,6 +103,7 @@
|
|||||||
$editStyle &&
|
$editStyle &&
|
||||||
$selection.has(item) &&
|
$selection.has(item) &&
|
||||||
$selection.getSelected().findIndex((i) => i.getFullId() === item.getFullId()) === 0;
|
$selection.getSelected().findIndex((i) => i.getFullId() === item.getFullId()) === 0;
|
||||||
|
$: hidden = item.level === ListLevel.WAYPOINTS ? node._data.hiddenWpt : node._data.hidden;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
@@ -142,7 +143,9 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<span
|
<span
|
||||||
class="w-full text-left truncate py-1 flex flex-row items-center"
|
class="w-full text-left truncate py-1 flex flex-row items-center {hidden
|
||||||
|
? 'text-muted-foreground'
|
||||||
|
: ''}"
|
||||||
on:contextmenu={(e) => {
|
on:contextmenu={(e) => {
|
||||||
if (e.ctrlKey) {
|
if (e.ctrlKey) {
|
||||||
// Add to selection instead of opening context menu
|
// Add to selection instead of opening context menu
|
||||||
@@ -181,7 +184,7 @@
|
|||||||
<span class="grow select-none truncate {$verticalFileView ? 'last:mr-2' : ''}">
|
<span class="grow select-none truncate {$verticalFileView ? 'last:mr-2' : ''}">
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
{#if (item.level !== ListLevel.WAYPOINTS && node._data.hidden) || (item.level === ListLevel.WAYPOINTS && node._data.hiddenWpt)}
|
{#if hidden}
|
||||||
<EyeOff
|
<EyeOff
|
||||||
size="12"
|
size="12"
|
||||||
class="shrink-0 mt-1 ml-1 {$verticalFileView ? 'mr-2' : ''} {item.level ===
|
class="shrink-0 mt-1 ml-1 {$verticalFileView ? 'mr-2' : ''} {item.level ===
|
||||||
|
@@ -35,7 +35,6 @@
|
|||||||
import { flyAndScale } from '$lib/utils';
|
import { flyAndScale } from '$lib/utils';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
import { TrackPoint } from 'gpx';
|
import { TrackPoint } from 'gpx';
|
||||||
import { produce } from 'immer';
|
|
||||||
|
|
||||||
export let popup: mapboxgl.Popup;
|
export let popup: mapboxgl.Popup;
|
||||||
export let popupElement: HTMLElement;
|
export let popupElement: HTMLElement;
|
||||||
|
@@ -413,7 +413,7 @@ export class RoutingControls {
|
|||||||
if (file.trk.length === 0) {
|
if (file.trk.length === 0) {
|
||||||
let track = new Track();
|
let track = new Track();
|
||||||
track.replaceTrackPoints(0, 0, 0, [newPoint]);
|
track.replaceTrackPoints(0, 0, 0, [newPoint]);
|
||||||
file.replaceTracks(0, 0, [track])[0];
|
file.replaceTracks(0, 0, [track]);
|
||||||
} else if (file.trk[trackIndex].trkseg.length === 0) {
|
} else if (file.trk[trackIndex].trkseg.length === 0) {
|
||||||
let segment = new TrackSegment();
|
let segment = new TrackSegment();
|
||||||
segment.replaceTrackPoints(0, 0, [newPoint]);
|
segment.replaceTrackPoints(0, 0, [newPoint]);
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import Dexie, { liveQuery } from 'dexie';
|
import Dexie, { liveQuery } from 'dexie';
|
||||||
import { GPXFile, GPXStatistics, Track, TrackSegment, Waypoint, TrackPoint, type Coordinates, distance, type LineStyleExtension } from 'gpx';
|
import { GPXFile, GPXStatistics, Track, TrackSegment, Waypoint, TrackPoint, type Coordinates, distance, type LineStyleExtension } from 'gpx';
|
||||||
import { enableMapSet, enablePatches, applyPatches, type Patch, type WritableDraft, castDraft, freeze, produceWithPatches, original, produce } from 'immer';
|
import { enableMapSet, enablePatches, applyPatches, type Patch, type WritableDraft, freeze, produceWithPatches } from 'immer';
|
||||||
import { writable, get, derived, type Readable, type Writable } from 'svelte/store';
|
import { writable, get, derived, type Readable, type Writable } from 'svelte/store';
|
||||||
import { gpxStatistics, initTargetMapBounds, splitAs, updateAllHidden, updateTargetMapBounds } from './stores';
|
import { gpxStatistics, initTargetMapBounds, splitAs, updateAllHidden, updateTargetMapBounds } from './stores';
|
||||||
import { mode } from 'mode-watcher';
|
import { mode } from 'mode-watcher';
|
||||||
@@ -13,7 +13,6 @@ import { SplitType } from '$lib/components/toolbar/tools/Scissors.svelte';
|
|||||||
enableMapSet();
|
enableMapSet();
|
||||||
enablePatches();
|
enablePatches();
|
||||||
|
|
||||||
|
|
||||||
class Database extends Dexie {
|
class Database extends Dexie {
|
||||||
|
|
||||||
fileids!: Dexie.Table<string, string>;
|
fileids!: Dexie.Table<string, string>;
|
||||||
@@ -179,7 +178,6 @@ function dexieGPXFileStore(id: string): Readable<GPXFileWithStatistics> & { dest
|
|||||||
let store = writable<GPXFileWithStatistics>(undefined);
|
let store = writable<GPXFileWithStatistics>(undefined);
|
||||||
let query = liveQuery(() => db.files.get(id)).subscribe(value => {
|
let query = liveQuery(() => db.files.get(id)).subscribe(value => {
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
console.log('File updated', id);
|
|
||||||
let gpx = new GPXFile(value);
|
let gpx = new GPXFile(value);
|
||||||
updateAnchorPoints(gpx);
|
updateAnchorPoints(gpx);
|
||||||
|
|
||||||
@@ -260,8 +258,6 @@ function updateSelection(updatedFiles: GPXFile[], deletedFileIds: string[]) {
|
|||||||
|
|
||||||
// Commit the changes to the file state to the database
|
// Commit the changes to the file state to the database
|
||||||
function commitFileStateChange(newFileState: ReadonlyMap<string, GPXFile>, patch: Patch[]) {
|
function commitFileStateChange(newFileState: ReadonlyMap<string, GPXFile>, patch: Patch[]) {
|
||||||
console.log(patch);
|
|
||||||
|
|
||||||
let changedFileIds = getChangedFileIds(patch);
|
let changedFileIds = getChangedFileIds(patch);
|
||||||
let updatedFileIds: string[] = [], deletedFileIds: string[] = [];
|
let updatedFileIds: string[] = [], deletedFileIds: string[] = [];
|
||||||
|
|
||||||
@@ -275,7 +271,6 @@ function commitFileStateChange(newFileState: ReadonlyMap<string, GPXFile>, patch
|
|||||||
|
|
||||||
let updatedFiles = updatedFileIds.map(id => newFileState.get(id)).filter(file => file !== undefined) as GPXFile[];
|
let updatedFiles = updatedFileIds.map(id => newFileState.get(id)).filter(file => file !== undefined) as GPXFile[];
|
||||||
updatedFileIds = updatedFiles.map(file => file._data.id);
|
updatedFileIds = updatedFiles.map(file => file._data.id);
|
||||||
console.log(updatedFileIds, deletedFileIds);
|
|
||||||
|
|
||||||
updateSelection(updatedFiles, deletedFileIds);
|
updateSelection(updatedFiles, deletedFileIds);
|
||||||
|
|
||||||
@@ -288,8 +283,6 @@ function commitFileStateChange(newFileState: ReadonlyMap<string, GPXFile>, patch
|
|||||||
await db.fileids.bulkDelete(deletedFileIds);
|
await db.fileids.bulkDelete(deletedFileIds);
|
||||||
await db.files.bulkDelete(deletedFileIds);
|
await db.files.bulkDelete(deletedFileIds);
|
||||||
}
|
}
|
||||||
}).catch((error) => {
|
|
||||||
console.error('Error committing file state change', error);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +308,6 @@ liveQuery(() => db.fileids.toArray()).subscribe(dbFileIds => {
|
|||||||
deletedFiles.forEach(id => {
|
deletedFiles.forEach(id => {
|
||||||
$files.get(id)?.destroy();
|
$files.get(id)?.destroy();
|
||||||
$files.delete(id);
|
$files.delete(id);
|
||||||
console.log('File removed', id);
|
|
||||||
});
|
});
|
||||||
return $files;
|
return $files;
|
||||||
});
|
});
|
||||||
@@ -559,10 +551,11 @@ export const dbUtils = {
|
|||||||
};
|
};
|
||||||
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
let file = draft.get(fileId);
|
let file = draft.get(fileId);
|
||||||
if (file) {
|
let originalFile = getFile(fileId);
|
||||||
|
if (file && originalFile) {
|
||||||
if (level === ListLevel.FILE) {
|
if (level === ListLevel.FILE) {
|
||||||
toMerge.trk.push(...file.replaceTracks(0, file.trk.length - 1, []));
|
toMerge.trk.push(...originalFile.trk.map((track) => track.clone()));
|
||||||
toMerge.wpt.push(...file.replaceWaypoints(0, file.wpt.length - 1, []));
|
toMerge.wpt.push(...originalFile.wpt.map((wpt) => wpt.clone()));
|
||||||
if (first) {
|
if (first) {
|
||||||
target = items[0];
|
target = items[0];
|
||||||
targetFile = file;
|
targetFile = file;
|
||||||
@@ -573,12 +566,12 @@ export const dbUtils = {
|
|||||||
if (level === ListLevel.TRACK) {
|
if (level === ListLevel.TRACK) {
|
||||||
items.forEach((item, index) => {
|
items.forEach((item, index) => {
|
||||||
let trackIndex = (item as ListTrackItem).getTrackIndex();
|
let trackIndex = (item as ListTrackItem).getTrackIndex();
|
||||||
|
toMerge.trkseg.splice(0, 0, ...originalFile.trk[trackIndex].trkseg.map((segment) => segment.clone()));
|
||||||
if (index === items.length - 1) { // Order is reversed, so the last track is the first one and the one to keep
|
if (index === items.length - 1) { // Order is reversed, so the last track is the first one and the one to keep
|
||||||
toMerge.trkseg.splice(0, 0, ...file.replaceTrackSegments(trackIndex, 0, file.trk[trackIndex].trkseg.length - 1, []));
|
|
||||||
target = item;
|
target = item;
|
||||||
|
file.trk[trackIndex].trkseg = [];
|
||||||
} else {
|
} else {
|
||||||
let removed = file.replaceTracks(trackIndex, trackIndex, []);
|
file.trk.splice(trackIndex, 1);
|
||||||
toMerge.trkseg.push(...removed[0].trkseg);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (level === ListLevel.SEGMENT) {
|
} else if (level === ListLevel.SEGMENT) {
|
||||||
@@ -588,7 +581,8 @@ export const dbUtils = {
|
|||||||
if (index === items.length - 1) { // Order is reversed, so the last segment is the first one and the one to keep
|
if (index === items.length - 1) { // Order is reversed, so the last segment is the first one and the one to keep
|
||||||
target = item;
|
target = item;
|
||||||
}
|
}
|
||||||
toMerge.trkseg.splice(0, 0, ...file.replaceTrackSegments(trackIndex, segmentIndex, segmentIndex, []));
|
toMerge.trkseg.splice(0, 0, originalFile.trk[trackIndex].trkseg[segmentIndex].clone());
|
||||||
|
file.trk[trackIndex].trkseg.splice(segmentIndex, 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
targetFile = file;
|
targetFile = file;
|
||||||
@@ -613,12 +607,9 @@ export const dbUtils = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (toMerge.trk.length > 0 && toMerge.trk[0].trkseg.length > 0) {
|
if (toMerge.trk.length > 0 && toMerge.trk[0].trkseg.length > 0) {
|
||||||
let s = toMerge.trk[0].trkseg[0];
|
let s = new TrackSegment();
|
||||||
toMerge.trk.map((track, trackIndex) => {
|
toMerge.trk.map((track) => {
|
||||||
track.trkseg.forEach((segment, segmentIndex) => {
|
track.trkseg.forEach((segment) => {
|
||||||
if (trackIndex === 0 && segmentIndex === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime);
|
s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -626,33 +617,26 @@ export const dbUtils = {
|
|||||||
toMerge.trk[0].trkseg = [s];
|
toMerge.trk[0].trkseg = [s];
|
||||||
}
|
}
|
||||||
if (toMerge.trkseg.length > 0) {
|
if (toMerge.trkseg.length > 0) {
|
||||||
let s = toMerge.trkseg[0];
|
let s = new TrackSegment();
|
||||||
toMerge.trkseg.forEach((segment, segmentIndex) => {
|
toMerge.trkseg.forEach((segment) => {
|
||||||
if (segmentIndex === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime);
|
s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime);
|
||||||
});
|
});
|
||||||
toMerge.trkseg = [s];
|
toMerge.trkseg = [s];
|
||||||
}
|
}
|
||||||
console.log(toMerge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetFile) {
|
if (targetFile) {
|
||||||
console.log(toMerge, target, targetFile);
|
|
||||||
if (target instanceof ListFileItem) {
|
if (target instanceof ListFileItem) {
|
||||||
targetFile.replaceTracks(0, targetFile.trk.length - 1, toMerge.trk)[0];
|
targetFile.replaceTracks(0, targetFile.trk.length - 1, toMerge.trk);
|
||||||
targetFile.replaceWaypoints(0, targetFile.wpt.length - 1, toMerge.wpt)[0];
|
targetFile.replaceWaypoints(0, targetFile.wpt.length - 1, toMerge.wpt);
|
||||||
} else if (target instanceof ListTrackItem) {
|
} else if (target instanceof ListTrackItem) {
|
||||||
let trackIndex = target.getTrackIndex();
|
let trackIndex = target.getTrackIndex();
|
||||||
targetFile.replaceTrackSegments(trackIndex, 0, -1, toMerge.trkseg)[0];
|
targetFile.replaceTrackSegments(trackIndex, 0, -1, toMerge.trkseg);
|
||||||
} else if (target instanceof ListTrackSegmentItem) {
|
} else if (target instanceof ListTrackSegmentItem) {
|
||||||
let trackIndex = target.getTrackIndex();
|
let trackIndex = target.getTrackIndex();
|
||||||
let segmentIndex = target.getSegmentIndex();
|
let segmentIndex = target.getSegmentIndex();
|
||||||
targetFile.replaceTrackSegments(trackIndex, segmentIndex, segmentIndex - 1, toMerge.trkseg)[0];
|
targetFile.replaceTrackSegments(trackIndex, segmentIndex, segmentIndex - 1, toMerge.trkseg);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(targetFile);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -721,14 +705,14 @@ export const dbUtils = {
|
|||||||
let newFile = file.clone();
|
let newFile = file.clone();
|
||||||
let tracks = track.trkseg.map((segment, segmentIndex) => {
|
let tracks = track.trkseg.map((segment, segmentIndex) => {
|
||||||
let t = track.clone();
|
let t = track.clone();
|
||||||
t.replaceTrackSegments(0, track.trkseg.length - 1, [segment])[0];
|
t.replaceTrackSegments(0, track.trkseg.length - 1, [segment]);
|
||||||
if (track.name) {
|
if (track.name) {
|
||||||
t.name = `${track.name} (${segmentIndex + 1})`;
|
t.name = `${track.name} (${segmentIndex + 1})`;
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
newFile.replaceTracks(0, file.trk.length - 1, tracks)[0];
|
newFile.replaceTracks(0, file.trk.length - 1, tracks);
|
||||||
newFile.replaceWaypoints(0, file.wpt.length - 1, closest.filter((c) => c.index.includes(index)).map((c) => file.wpt[c.wptIndex]))[0];
|
newFile.replaceWaypoints(0, file.wpt.length - 1, closest.filter((c) => c.index.includes(index)).map((c) => file.wpt[c.wptIndex]));
|
||||||
newFile._data.id = fileIds[index];
|
newFile._data.id = fileIds[index];
|
||||||
newFile.metadata.name = track.name ?? `${file.metadata.name} (${index + 1})`;
|
newFile.metadata.name = track.name ?? `${file.metadata.name} (${index + 1})`;
|
||||||
draft.set(newFile._data.id, freeze(newFile));
|
draft.set(newFile._data.id, freeze(newFile));
|
||||||
@@ -759,8 +743,8 @@ export const dbUtils = {
|
|||||||
|
|
||||||
file.trk[0].trkseg.forEach((segment, index) => {
|
file.trk[0].trkseg.forEach((segment, index) => {
|
||||||
let newFile = file.clone();
|
let newFile = file.clone();
|
||||||
newFile.replaceTrackSegments(0, 0, file.trk[0].trkseg.length - 1, [segment])[0];
|
newFile.replaceTrackSegments(0, 0, file.trk[0].trkseg.length - 1, [segment]);
|
||||||
newFile.replaceWaypoints(0, file.wpt.length - 1, closest.filter((c) => c.index.includes(index)).map((c) => file.wpt[c.wptIndex]))[0];
|
newFile.replaceWaypoints(0, file.wpt.length - 1, closest.filter((c) => c.index.includes(index)).map((c) => file.wpt[c.wptIndex]));
|
||||||
newFile._data.id = fileIds[index];
|
newFile._data.id = fileIds[index];
|
||||||
newFile.metadata.name = `${file.trk[0].name ?? file.metadata.name} (${index + 1})`;
|
newFile.metadata.name = `${file.trk[0].name ?? file.metadata.name} (${index + 1})`;
|
||||||
draft.set(newFile._data.id, freeze(newFile));
|
draft.set(newFile._data.id, freeze(newFile));
|
||||||
@@ -776,13 +760,13 @@ export const dbUtils = {
|
|||||||
let track = file.trk[trackIndex];
|
let track = file.trk[trackIndex];
|
||||||
let tracks = track.trkseg.map((segment, segmentIndex) => {
|
let tracks = track.trkseg.map((segment, segmentIndex) => {
|
||||||
let t = track.clone();
|
let t = track.clone();
|
||||||
t.replaceTrackSegments(0, track.trkseg.length - 1, [segment])[0];
|
t.replaceTrackSegments(0, track.trkseg.length - 1, [segment]);
|
||||||
if (track.name) {
|
if (track.name) {
|
||||||
t.name = `${track.name} (${segmentIndex + 1})`;
|
t.name = `${track.name} (${segmentIndex + 1})`;
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
file.replaceTracks(trackIndex, trackIndex, tracks)[0];
|
file.replaceTracks(trackIndex, trackIndex, tracks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user