Starting to implement a proper UI for GPX import.
This commit is contained in:
parent
3a5f5260c8
commit
31bec02496
|
@ -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>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
|
@ -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;
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -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)}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue