diff --git a/website/src/lib/components/file-list/FileList.ts b/website/src/lib/components/file-list/FileList.ts
index ac5f4be4..5c18a6e7 100644
--- a/website/src/lib/components/file-list/FileList.ts
+++ b/website/src/lib/components/file-list/FileList.ts
@@ -1,8 +1,9 @@
import { dbUtils, fileObservers } from "$lib/db";
-import { castDraft } from "immer";
+import { castDraft, freeze } from "immer";
import { Track, TrackSegment, Waypoint } from "gpx";
import { selection } from "./Selection";
import { get } from "svelte/store";
+import { newGPXFile } from "$lib/stores";
export enum ListLevel {
ROOT,
@@ -273,7 +274,7 @@ export function moveItems(fromParent: ListItem, toParent: ListItem, fromItems: L
}
});
- dbUtils.applyEachToFiles([fromParent.getFileId(), toParent.getFileId()], [
+ dbUtils.applyEachToFilesAndGlobal([fromParent.getFileId(), toParent.getFileId()], [
(file, context: (Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
let newFile = file;
fromItems.forEach((item) => {
@@ -301,15 +302,27 @@ export function moveItems(fromParent: ListItem, toParent: ListItem, fromItems: L
(file, context: (Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
let newFile = file;
toItems.forEach((item, i) => {
- if (item instanceof ListTrackItem && context[i] instanceof Track) {
- let [result, _removed] = newFile.replaceTracks(item.getTrackIndex(), item.getTrackIndex() - 1, [context[i]]);
- newFile = castDraft(result);
+ if (item instanceof ListTrackItem) {
+ if (context[i] instanceof Track) {
+ let [result, _removed] = newFile.replaceTracks(item.getTrackIndex(), item.getTrackIndex() - 1, [context[i]]);
+ newFile = castDraft(result);
+ } else if (context[i] instanceof TrackSegment) {
+ let [result, _removed] = newFile.replaceTracks(item.getTrackIndex(), item.getTrackIndex() - 1, [new Track({
+ trkseg: [context[i]]
+ })]);
+ newFile = castDraft(result);
+ }
} else if (item instanceof ListTrackSegmentItem && context[i] instanceof TrackSegment) {
let [result, _removed] = newFile.replaceTrackSegments(item.getTrackIndex(), item.getSegmentIndex(), item.getSegmentIndex() - 1, [context[i]]);
newFile = castDraft(result);
- } else if (item instanceof ListWaypointsItem && Array.isArray(context[i]) && context[i].length > 0 && context[i][0] instanceof Waypoint) {
- let [result, _removed] = newFile.replaceWaypoints(newFile.wpt.length, newFile.wpt.length - 1, context[i]);
- newFile = castDraft(result);
+ } else if (item instanceof ListWaypointsItem) {
+ if (Array.isArray(context[i]) && context[i].length > 0 && context[i][0] instanceof Waypoint) {
+ let [result, _removed] = newFile.replaceWaypoints(newFile.wpt.length, newFile.wpt.length - 1, context[i]);
+ newFile = castDraft(result);
+ } else if (context[i] instanceof Waypoint) {
+ let [result, _removed] = newFile.replaceWaypoints(newFile.wpt.length, newFile.wpt.length - 1, [context[i]]);
+ newFile = castDraft(result);
+ }
} else if (item instanceof ListWaypointItem && context[i] instanceof Waypoint) {
let [result, _removed] = newFile.replaceWaypoints(item.getWaypointIndex(), item.getWaypointIndex() - 1, [context[i]]);
newFile = castDraft(result);
@@ -317,13 +330,26 @@ export function moveItems(fromParent: ListItem, toParent: ListItem, fromItems: L
});
return newFile;
}
- ], []);
-
- selection.update(($selection) => {
- $selection.clear();
- toItems.forEach((item) => {
- $selection.set(item, true);
+ ], (files, context: (Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
+ toItems.forEach((item, i) => {
+ if (item instanceof ListFileItem) {
+ if (context[i] instanceof Track) {
+ let newFile = newGPXFile();
+ newFile._data.id = item.getFileId();
+ if (context[i].name) {
+ newFile.metadata.name = context[i].name;
+ }
+ newFile = newFile.replaceTracks(0, 0, [context[i]])[0];
+ files.set(item.getFileId(), freeze(newFile));
+ } else if (context[i] instanceof TrackSegment) {
+ let newFile = newGPXFile();
+ newFile._data.id = item.getFileId();
+ newFile = newFile.replaceTracks(0, 0, [new Track({
+ trkseg: [context[i]]
+ })])[0];
+ files.set(item.getFileId(), freeze(newFile));
+ }
+ }
});
- return $selection;
- });
+ }, []);
}
diff --git a/website/src/lib/components/file-list/FileListNodeContent.svelte b/website/src/lib/components/file-list/FileListNodeContent.svelte
index b2924727..d3a134bf 100644
--- a/website/src/lib/components/file-list/FileListNodeContent.svelte
+++ b/website/src/lib/components/file-list/FileListNodeContent.svelte
@@ -1,12 +1,25 @@
+
+
{#if node instanceof Map}
{#each node as [fileId, file] (fileId)}
diff --git a/website/src/lib/components/file-list/Selection.ts b/website/src/lib/components/file-list/Selection.ts
index 5f4e8969..0df7c316 100644
--- a/website/src/lib/components/file-list/Selection.ts
+++ b/website/src/lib/components/file-list/Selection.ts
@@ -1,5 +1,5 @@
import { get, writable } from "svelte/store";
-import { ListFileItem, ListItem, ListRootItem, ListTrackItem, ListTrackSegmentItem, ListWaypointItem, type ListLevel, sortItems } from "./FileList";
+import { ListFileItem, ListItem, ListRootItem, ListTrackItem, ListTrackSegmentItem, ListWaypointItem, type ListLevel, sortItems, ListWaypointsItem } from "./FileList";
import { fileObservers, settings } from "$lib/db";
export class SelectionTreeType {
@@ -205,7 +205,7 @@ export function applyToOrderedSelectedItemsFromFile(callback: (fileId: string, l
get(selection).forEach((item) => {
if (item.getFileId() === fileId) {
level = item.level;
- if (item instanceof ListFileItem || item instanceof ListTrackItem || item instanceof ListTrackSegmentItem || item instanceof ListWaypointItem) {
+ if (item instanceof ListFileItem || item instanceof ListTrackItem || item instanceof ListTrackSegmentItem || item instanceof ListWaypointsItem || item instanceof ListWaypointItem) {
items.push(item);
}
}
diff --git a/website/src/lib/db.ts b/website/src/lib/db.ts
index 6985d5df..dec679ca 100644
--- a/website/src/lib/db.ts
+++ b/website/src/lib/db.ts
@@ -187,17 +187,13 @@ function dexieGPXFileStore(id: string): Readable
& { dest
}
// Add/update the files to the database
-function updateDbFiles(files: (GPXFile | undefined)[], add: boolean = false) {
+function updateDbFiles(files: (GPXFile | undefined)[]) {
let filteredFiles = files.filter(file => file !== undefined) as GPXFile[];
let fileIds = filteredFiles.map(file => file._data.id);
- if (add) {
- return db.transaction('rw', db.fileids, db.files, async () => {
- await db.fileids.bulkAdd(fileIds, fileIds);
- await db.files.bulkAdd(filteredFiles, fileIds);
- });
- } else {
- return db.files.bulkPut(filteredFiles, fileIds);
- }
+ return db.transaction('rw', db.fileids, db.files, async () => {
+ await db.fileids.bulkPut(fileIds, fileIds);
+ await db.files.bulkPut(filteredFiles, fileIds);
+ });
}
// Delete the files with the given ids from the database
@@ -210,9 +206,7 @@ function deleteDbFiles(fileIds: string[]) {
// Commit the changes to the file state to the database
function commitFileStateChange(newFileState: ReadonlyMap, patch: Patch[]) {
- if (newFileState.size > fileState.size) {
- return updateDbFiles(getChangedFileIds(patch).map((fileId) => newFileState.get(fileId)), true);
- } else if (newFileState.size === fileState.size) {
+ if (newFileState.size >= fileState.size) {
return updateDbFiles(getChangedFileIds(patch).map((fileId) => newFileState.get(fileId)));
} else {
return deleteDbFiles(getChangedFileIds(patch));
@@ -252,6 +246,20 @@ liveQuery(() => db.fileids.toArray()).subscribe(dbFileIds => {
return $selection;
});
}
+ settings.fileOrder.update((order) => {
+ newFiles.forEach((fileId) => {
+ if (!order.includes(fileId)) {
+ order.push(fileId);
+ }
+ });
+ deletedFiles.forEach((fileId) => {
+ let index = order.indexOf(fileId);
+ if (index !== -1) {
+ order.splice(index, 1);
+ }
+ });
+ return order;
+ });
}
});
@@ -292,7 +300,7 @@ function applyToFiles(fileIds: string[], callback: (file: WritableDraft
}
// Helper function to apply different callbacks to multiple files
-function applyEachToFiles(fileIds: string[], callbacks: ((file: WritableDraft, context?: any) => GPXFile)[], context?: any) {
+function applyEachToFilesAndGlobal(fileIds: string[], callbacks: ((file: WritableDraft, context?: any) => GPXFile)[], globalCallback: (files: Map, context?: any) => void, context?: any) {
const [newFileState, patch, inversePatch] = produceWithPatches(fileState, (draft) => {
fileIds.forEach((fileId, index) => {
let file = draft.get(fileId);
@@ -300,6 +308,7 @@ function applyEachToFiles(fileIds: string[], callbacks: ((file: WritableDraft) => GPXFile) => {
applyToFiles(ids, callback);
},
- applyEachToFiles: (ids: string[], callbacks: ((file: WritableDraft, context?: any) => GPXFile)[], context?: any) => {
- applyEachToFiles(ids, callbacks, context);
+ applyEachToFilesAndGlobal: (ids: string[], callbacks: ((file: WritableDraft, context?: any) => GPXFile)[], globalCallback: (files: Map, context?: any) => void, context?: any) => {
+ applyEachToFilesAndGlobal(ids, callbacks, globalCallback, context);
},
applyToSelection: (callback: (file: WritableDraft) => AnyGPXTreeElement) => {
if (get(selection).size === 0) {
diff --git a/website/src/lib/stores.ts b/website/src/lib/stores.ts
index b7123f10..b3ae4e16 100644
--- a/website/src/lib/stores.ts
+++ b/website/src/lib/stores.ts
@@ -127,9 +127,14 @@ export enum Tool {
}
export const currentTool = writable(null);
-export function createFile() {
+export function newGPXFile() {
let file = new GPXFile();
file.metadata.name = get(_)("menu.new_filename");
+ return file;
+}
+
+export function createFile() {
+ let file = newGPXFile();
dbUtils.add(file);