Starting to implement a proper UI for GPX import.

This commit is contained in:
Eric van der Vlist 2022-12-11 16:20:34 +01:00
parent 3a5f5260c8
commit 31bec02496
7 changed files with 165 additions and 57 deletions

View File

@ -1,4 +1,4 @@
import { Component } from 'solid-js'; import { Component, createSignal, Show } from 'solid-js';
import CloudUploadIcon from '@suid/icons-material/CloudUpload'; import CloudUploadIcon from '@suid/icons-material/CloudUpload';
@ -9,57 +9,70 @@ import css from './GpxImport.module.css';
import { findStartTime } from '../../lib/gpx'; import { findStartTime } from '../../lib/gpx';
import dispatch from '../../workers/dispatcher-main'; import dispatch from '../../workers/dispatcher-main';
import { intToGpxId } from '../../lib/ids'; import { intToGpxId } from '../../lib/ids';
import Dialog from '../dialog';
import { useI18n } from '@solid-primitives/i18n';
import { Box, Grid, Typography } from '@suid/material';
import GpxImportSingleFile from './GpxImportSingleFile';
const GpxImport: Component = () => { const GpxImport: Component = () => {
const [filesToImport, setFilesToImport] = createSignal<FileList>();
const [t] = useI18n();
const onChangeHandler = (event: any) => { const onChangeHandler = (event: any) => {
console.log({ console.log({
caller: 'GpxImport / On change handler', caller: 'GpxImport / On change handler',
files: event.target.files, files: event.target.files,
}); });
for (const file of event.target.files) { setFilesToImport(event.target.files);
const fileReader = new FileReader(); // for (const file of event.target.files) {
fileReader.readAsText(file); // const fileReader = new FileReader();
// fileReader.readAsText(file);
fileReader.addEventListener( // fileReader.addEventListener(
'load', // 'load',
async () => { // async () => {
// this will then display a text file // // this will then display a text file
console.log({ // console.log({
caller: 'GpxImport / XML', // caller: 'GpxImport / XML',
file, // file,
result: fileReader.result, // result: fileReader.result,
}); // });
const gpx = GPX.parse(fileReader.result); // const gpx = GPX.parse(fileReader.result);
console.log({ caller: 'GpxImport / JSON', file, gpx }); // console.log({ caller: 'GpxImport / JSON', file, gpx });
if (gpx) { // if (gpx) {
const startTime = new Date(findStartTime(gpx)!); // const startTime = new Date(findStartTime(gpx)!);
await dispatch({ // await dispatch({
action: 'pruneAndSaveImportedGpx', // action: 'pruneAndSaveImportedGpx',
params: { // params: {
id: { gpx: intToGpxId(startTime.valueOf()) }, // id: { gpx: intToGpxId(startTime.valueOf()) },
gpx: gpx, // gpx: gpx,
tech: { // tech: {
lastModified: new Date(file.lastModified).toISOString(), // lastModified: new Date(file.lastModified).toISOString(),
importDate: new Date().toISOString(), // importDate: new Date().toISOString(),
name: file.name, // name: file.name,
size: file.size, // size: file.size,
type: file.type, // type: file.type,
}, // },
}, // },
}); // });
console.log({ caller: 'GpxImport / JSON / done', file, gpx }); // console.log({ caller: 'GpxImport / JSON / done', file, gpx });
} else { // } else {
console.error({ // console.error({
message: "can't parse GPX file", // message: "can't parse GPX file",
file, // file,
xml: fileReader.result, // xml: fileReader.result,
}); // });
} // }
// TODO: error handling // // TODO: error handling
}, // },
false // false
); // );
} // }
};
const handleClose = () => {
setFilesToImport(undefined);
}; };
return ( return (
@ -77,6 +90,19 @@ const GpxImport: Component = () => {
onChange={onChangeHandler} onChange={onChangeHandler}
/> />
</div> </div>
<Dialog
open={filesToImport() !== undefined}
title={t('gpxImport')}
closeHandler={handleClose}
>
<Box
sx={{
width: '100%',
}}
>
<GpxImportSingleFile gpxFile={filesToImport()[0]} />
</Box>
</Dialog>
</> </>
); );
}; };

View File

@ -0,0 +1,71 @@
import { useI18n } from '@solid-primitives/i18n';
import { Grid, Typography } from '@suid/material';
import { Component, createSignal, Show } from 'solid-js';
import { findStartTime } from '../../lib/gpx';
import GPX from '../../lib/gpx-parser-builder/src/gpx';
interface Props {
gpxFile: File;
}
const analyzeGpx = (gpx: Gpx | undefined) => {
if (gpx === undefined) {
return {};
}
const stats = {
creator: gpx.$.creator,
nbWpts: gpx.wpt ? gpx.wpt?.length : 0,
nbRtes: gpx.rte ? gpx.rte?.length : 0,
nbTrks: gpx.trk ? gpx.trk?.length : 0,
};
return stats;
};
const GpxImportSingleFile: Component<Props> = ({ gpxFile }) => {
const [t] = useI18n();
const [gpx, setGpx] = createSignal<Gpx>();
const gpxReader = new FileReader();
gpxReader.readAsText(gpxFile);
gpxReader.addEventListener(
'load',
async () => {
// this will then display a text gpxfile
console.log({
caller: 'GpxImportSingleFile / XML',
gpxFile,
result: gpxReader.result,
});
const gpx = GPX.parse(gpxReader.result);
console.log({ caller: 'GpxImportSingleFile / JSON', gpxFile, gpx });
setGpx(gpx);
// if (gpx) {
// const startTime = new Date(findStartTime(gpx)!);
// }
},
false
);
const stats = analyzeGpx(gpx());
return (
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant='subtitle1'>
{t('file')}
{gpxFile.name}
</Typography>
</Grid>
<Show when={gpx() !== undefined}>
<Grid item xs={12}>
<Typography variant='body1'>
{t('gpxStats', analyzeGpx(gpx()))}
</Typography>
</Grid>
</Show>
</Grid>
);
};
export default GpxImportSingleFile;

View File

@ -50,7 +50,7 @@ const changeHandler = async (change: any) => {
(doc) => { (doc) => {
console.log({ caller: 'changeHandler / gpxes', doc }); console.log({ caller: 'changeHandler / gpxes', doc });
doc.push(id); doc.push(id);
doc.sort().reverse(); doc.reverse().sort().reverse();
return doc; return doc;
}, },
[] []

View File

@ -20,13 +20,10 @@ export const put = async (
db.put({ _id, _rev: current._rev, type, doc: update(current.doc) }); db.put({ _id, _rev: current._rev, type, doc: update(current.doc) });
} catch (error: any) { } catch (error: any) {
if (error.name === 'conflict') { if (error.name === 'conflict') {
console.log({ caller: 'db.put', _id, type, defaultDoc, error });
await put(_id, type, update, defaultDoc); await put(_id, type, update, defaultDoc);
} else { } else {
console.error( console.error({ caller: 'db.put', _id, type, defaultDoc, error });
`put(${_id}, ${JSON.stringify(
update(current.doc)
)}), error: ${JSON.stringify(error)}`
);
} }
} }
}; };

View File

@ -20,6 +20,11 @@ const dict = {
save: 'SAVE', save: 'SAVE',
cancel: 'CANCEL', cancel: 'CANCEL',
gpxImport: 'GPX import',
file: 'File: ',
gpxStats:
'This file has been created with "{{creator}}" and includes {{nbWpts}} place(s), {{nbRte}} routes(s) et {{nbTrks}} track(s).',
}; };
export default dict; export default dict;

View File

@ -16,14 +16,17 @@ const dict = {
'rte-start': 'début de route', 'rte-start': 'début de route',
'rte-finish': 'fin de route', 'rte-finish': 'fin de route',
name: 'Nom', name: 'Nom',
sym: 'Symbole', sym: 'Symbole',
minZoom: 'Niveau de zoom minimum', minZoom: 'Niveau de zoom minimum',
save: 'SAUVEGARDER', save: 'SAUVEGARDER',
cancel: 'ANNULER', cancel: 'ANNULER',
gpxImport: 'Import de fichier(s) GPX ',
file: 'Fichier\u00a0: ',
gpxStats:
'Ce fichier a été créé avec "{{creator}}" et contient {{nbWpts}} lieu(x), {{nbRtes}} itineraire(s) et {{nbTrks}} trace(s).',
}; };
export default dict; export default dict;

View File

@ -3,10 +3,16 @@ import Link from './link';
export default class Waypoint { export default class Waypoint {
constructor(object) { constructor(object) {
this.$ = {}; this.$ = {};
this.$.lat = object.$.lat === 0 || object.lat === 0 ? 0 : object.$.lat || object.lat || -1; this.$.lat =
this.$.lon = object.$.lon === 0 || object.lon === 0 ? 0 : object.$.lon || object.lon || -1; object.$.lat === 0 || object.lat === 0
? 0
: object.$.lat || object.lat || -1;
this.$.lon =
object.$.lon === 0 || object.lon === 0
? 0
: object.$.lon || object.lon || -1;
this.ele = object.ele; this.ele = object.ele;
this.time = object.time ? new Date(object.time) : new Date(); this.time = object.time ? new Date(object.time) : undefined;
this.magvar = object.magvar; this.magvar = object.magvar;
this.geoidheight = object.geoidheight; this.geoidheight = object.geoidheight;
this.name = object.name; this.name = object.name;
@ -26,7 +32,7 @@ export default class Waypoint {
if (!Array.isArray(object.link)) { if (!Array.isArray(object.link)) {
object.link = [object.link]; object.link = [object.link];
} }
this.link = object.link.map(l => new Link(l)); this.link = object.link.map((l) => new Link(l));
} }
} }
} }