mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-10-27 02:27:18 +00:00
progress
This commit is contained in:
1 parent
ce8398f749
commit
41b9116c6a
60 files changed
+7525
-340
No files matched your search
@@ -0,0 +1,217 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { RouteAttributes, StorageOpened } from 'gpx-rs';
|
||||
import type { Backend } from './types';
|
||||
|
||||
/** An array that a command returns as its bytes. */
|
||||
const array = async <T>(
|
||||
command: string,
|
||||
type: { new (buffer: ArrayBuffer): T },
|
||||
args?: Record<string, unknown>
|
||||
) => new type(await invoke<ArrayBuffer>(command, args));
|
||||
|
||||
/** Like `array`, for the arrays that can be absent: the first byte tells whether they are there. */
|
||||
const optionalArray = async <T>(
|
||||
command: string,
|
||||
type: { new (buffer: ArrayBuffer): T },
|
||||
args?: Record<string, unknown>
|
||||
) => {
|
||||
const bytes = await invoke<ArrayBuffer>(command, args);
|
||||
return new Uint8Array(bytes)[0] === 1 ? new type(bytes.slice(1)) : undefined;
|
||||
};
|
||||
|
||||
const category = (c?: RouteAttributes['surface']) =>
|
||||
c && { starts: Array.from(c.starts), values: Array.from(c.values), names: c.names };
|
||||
|
||||
/**
|
||||
* The engine in the Rust process of the desktop app, reached through its commands (see
|
||||
* `tauri/src/commands`). Typed arrays are returned as bytes, little-endian.
|
||||
*/
|
||||
export async function createTauriBackend(): Promise<Backend> {
|
||||
const f64 = (command: string, args?: Record<string, unknown>) =>
|
||||
array(command, Float64Array, args);
|
||||
const u32 = (command: string) => array(command, Uint32Array);
|
||||
const u8 = (command: string) => array(command, Uint8Array);
|
||||
const f64Optional = (command: string) => optionalArray(command, Float64Array);
|
||||
|
||||
return {
|
||||
select: (fileIds, mode) => invoke('select', { fileIds, mode }),
|
||||
select_all: () => invoke('select_all'),
|
||||
arrow_select: (down, add) => invoke('arrow_select', { down, add }),
|
||||
select_tracks: (fileId, trackIds, mode) =>
|
||||
invoke('select_tracks', { fileId, trackIds, mode }),
|
||||
select_segments: (fileId, trackId, segmentIds, mode) =>
|
||||
invoke('select_segments', { fileId, trackId, segmentIds, mode }),
|
||||
select_waypoint_group: (fileId, mode) => invoke('select_waypoint_group', { fileId, mode }),
|
||||
select_waypoints: (fileId, waypointIds, mode) =>
|
||||
invoke('select_waypoints', { fileId, waypointIds, mode }),
|
||||
|
||||
undo: () => invoke('undo'),
|
||||
redo: () => invoke('redo'),
|
||||
copy: () => invoke('copy'),
|
||||
cut: () => invoke('cut'),
|
||||
paste: () => invoke('paste'),
|
||||
|
||||
new_file: (name, lng, lat, ele) => invoke('new_file', { name, lng, lat, ele }),
|
||||
load_files: (files) => {
|
||||
const data = new Uint8Array(files.reduce((sum, file) => sum + file.data.length, 0));
|
||||
let offset = 0;
|
||||
for (const file of files) {
|
||||
data.set(file.data, offset);
|
||||
offset += file.data.length;
|
||||
}
|
||||
// headers are ASCII
|
||||
const header = (value: unknown) => encodeURIComponent(JSON.stringify(value));
|
||||
return invoke('load_files', data, {
|
||||
headers: {
|
||||
lengths: header(files.map((file) => file.data.length)),
|
||||
names: header(files.map((file) => file.name)),
|
||||
},
|
||||
});
|
||||
},
|
||||
duplicate: () => invoke('duplicate'),
|
||||
delete: (wholeFiles) => invoke('delete', { wholeFiles }),
|
||||
delete_all: () => invoke('delete_all'),
|
||||
reorder: (fileIds, index) => invoke('reorder', { fileIds, index }),
|
||||
// an infinite index is the end of the list, which JSON cannot tell
|
||||
move_elements: (what, to) =>
|
||||
invoke('move_elements', {
|
||||
what,
|
||||
to: { ...to, index: Math.min(to.index, Number.MAX_SAFE_INTEGER) },
|
||||
}),
|
||||
metadata: (name, desc) => invoke('metadata', { name, desc }),
|
||||
style: (color, opacity, width) => invoke('style', { color, opacity, width }),
|
||||
new_track: () => invoke('new_track'),
|
||||
new_track_segment: () => invoke('new_track_segment'),
|
||||
|
||||
new_waypoint: (lng, lat, ele, name, desc, icon, link) =>
|
||||
invoke('new_waypoint', { lng, lat, ele, name, desc, icon, link }),
|
||||
update_waypoint: (fileId, waypointId, lng, lat, ele, name, desc, icon, link) =>
|
||||
invoke('update_waypoint', {
|
||||
fileId,
|
||||
waypointId,
|
||||
lng,
|
||||
lat,
|
||||
ele,
|
||||
name,
|
||||
desc,
|
||||
icon,
|
||||
link,
|
||||
}),
|
||||
move_waypoint: (fileId, waypointId, lng, lat, ele) =>
|
||||
invoke('move_waypoint', { fileId, waypointId, lng, lat, ele }),
|
||||
delete_waypoint: (fileId, waypointId) => invoke('delete_waypoint', { fileId, waypointId }),
|
||||
|
||||
reverse: () => invoke('reverse'),
|
||||
extract: () => invoke('extract'),
|
||||
round_trip: () => invoke('round_trip'),
|
||||
elevation: (ele) => invoke('elevation', { ele: Array.from(ele) }),
|
||||
change_timestamps: (startTime, speed, ratio) =>
|
||||
invoke('change_timestamps', { startTime, speed, ratio }),
|
||||
create_artificial_timestamps: (startTime, totalTime) =>
|
||||
invoke('create_artificial_timestamps', { startTime, totalTime }),
|
||||
clean: (west, south, east, north, inside, trkpt, wpt) =>
|
||||
invoke('clean', {
|
||||
west,
|
||||
south,
|
||||
east,
|
||||
north,
|
||||
cleanType: inside ? 'inside' : 'outside',
|
||||
trkpt,
|
||||
wpt,
|
||||
}),
|
||||
merge: (mergeType, removeGaps) => invoke('merge', { mergeType, removeGaps }),
|
||||
reduce: (tolerance) => invoke('reduce', { tolerance }),
|
||||
crop: (start, end) => invoke('crop', { start, end }),
|
||||
split: (revision, at, splitType) => invoke('split', { revision, at, splitType }),
|
||||
route: (revision, start, end, lng, lat, ele, attributes, anchors) =>
|
||||
invoke('route', {
|
||||
revision,
|
||||
start,
|
||||
end,
|
||||
lng: Array.from(lng),
|
||||
lat: Array.from(lat),
|
||||
ele: Array.from(ele),
|
||||
attributes: {
|
||||
surface: category(attributes.surface),
|
||||
highway: category(attributes.highway),
|
||||
sacScale: category(attributes.sacScale),
|
||||
mtbScale: category(attributes.mtbScale),
|
||||
},
|
||||
anchors: Array.from(anchors),
|
||||
}),
|
||||
insert_anchor: (revision, lng, lat) => invoke('insert_anchor', { revision, lng, lat }),
|
||||
change_loop_start: (revision, index) => invoke('change_loop_start', { revision, index }),
|
||||
|
||||
can_undo: () => invoke('can_undo'),
|
||||
can_redo: () => invoke('can_redo'),
|
||||
can_paste: () => invoke('can_paste'),
|
||||
clipboard: async () => (await invoke('clipboard')) ?? undefined,
|
||||
selection: () => invoke('selection'),
|
||||
file_order: () => invoke('file_order'),
|
||||
file_structure: async (fileId) => (await invoke('file_structure', { fileId })) ?? undefined,
|
||||
file_statistics: async (fileId) =>
|
||||
(await invoke('file_statistics', { fileId })) ?? undefined,
|
||||
waypoint: async (fileId, waypointId) =>
|
||||
(await invoke('waypoint', { fileId, waypointId })) ?? undefined,
|
||||
trackpoint: async (fileId, segmentId, index) =>
|
||||
(await invoke('trackpoint', { fileId, segmentId, index })) ?? undefined,
|
||||
export_file: async (fileId, time, hr, cad, atemp, power, osm, asRoute) => {
|
||||
const file = await optionalArray('export_file', Uint8Array, {
|
||||
fileId,
|
||||
time,
|
||||
hr,
|
||||
cad,
|
||||
atemp,
|
||||
power,
|
||||
osm,
|
||||
asRoute,
|
||||
});
|
||||
return file as Uint8Array<ArrayBuffer> | undefined;
|
||||
},
|
||||
exportable_data: (fileIds) => invoke('exportable_data', { fileIds }),
|
||||
reduction_distances: () => f64('reduction_distances'),
|
||||
segment_coordinates: (segmentId) => f64('segment_coordinates', { segmentId }),
|
||||
waypoint_coordinates: (fileId) => f64('waypoint_coordinates', { fileId }),
|
||||
|
||||
selection_statistics: () => invoke('selection_statistics'),
|
||||
slice_statistics: async (start, end) =>
|
||||
(await invoke('slice_statistics', { start, end })) ?? undefined,
|
||||
total_distance: () => f64('total_distance'),
|
||||
slope: () => f64('slope'),
|
||||
lng: () => f64('lng'),
|
||||
lat: () => f64('lat'),
|
||||
ele: () => f64('ele'),
|
||||
timestamps: () => optionalArray('timestamps', BigInt64Array),
|
||||
speed: () => f64Optional('speed'),
|
||||
hr: () => f64Optional('hr'),
|
||||
cad: () => f64Optional('cad'),
|
||||
atemp: () => f64Optional('atemp'),
|
||||
power: () => f64Optional('power'),
|
||||
slope_segment_slope: () => f64('slope_segment_slope'),
|
||||
slope_segment_distance: () => f64('slope_segment_distance'),
|
||||
surface_starts: () => u32('surface_starts'),
|
||||
surface_values: () => u8('surface_values'),
|
||||
surfaces: () => invoke('surfaces'),
|
||||
highway_starts: () => u32('highway_starts'),
|
||||
highway_values: () => u8('highway_values'),
|
||||
highways: () => invoke('highways'),
|
||||
sac_scale_starts: () => u32('sac_scale_starts'),
|
||||
sac_scale_values: () => u8('sac_scale_values'),
|
||||
sac_scales: () => invoke('sac_scales'),
|
||||
mtb_scale_starts: () => u32('mtb_scale_starts'),
|
||||
mtb_scale_values: () => u8('mtb_scale_values'),
|
||||
mtb_scales: () => invoke('mtb_scales'),
|
||||
anchor_indices: () => u32('anchor_indices'),
|
||||
anchor_zooms: () => u8('anchor_zooms'),
|
||||
segment_starts: () => u32('segment_starts'),
|
||||
segment_ids: () => invoke('segment_ids'),
|
||||
routing_revision: () => invoke('routing_revision'),
|
||||
|
||||
importsLegacyData: false,
|
||||
open_storage: () => invoke<StorageOpened>('open_storage'),
|
||||
flush_storage: () => invoke('flush_storage'),
|
||||
sync_storage: () => invoke('sync_storage'),
|
||||
set_setting: (key, value) => invoke('set_setting', { key, value }),
|
||||
delete_setting: (key) => invoke('delete_setting', { key }),
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user