Basic dialog to start/pause/stop and clear track recording.
This commit is contained in:
parent
d71881dc02
commit
3235d9ae70
|
@ -1,15 +1,30 @@
|
||||||
import React, { useState } from 'react';
|
import React, { Fragment, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { useDB } from 'react-pouchdb';
|
|
||||||
|
|
||||||
|
import { useDB, useFind } from 'react-pouchdb';
|
||||||
|
|
||||||
import '../../theme/get-location.css';
|
import '../../theme/get-location.css';
|
||||||
import { IonButton, IonIcon } from '@ionic/react';
|
import {
|
||||||
import { recordingOutline, recording } from 'ionicons/icons';
|
createAnimation,
|
||||||
|
IonButton,
|
||||||
|
IonButtons,
|
||||||
|
IonContent,
|
||||||
|
IonIcon,
|
||||||
|
IonModal,
|
||||||
|
IonTitle,
|
||||||
|
IonToolbar,
|
||||||
|
} from '@ionic/react';
|
||||||
|
import {
|
||||||
|
recordingOutline,
|
||||||
|
recording,
|
||||||
|
closeCircle,
|
||||||
|
pauseCircle,
|
||||||
|
stop,
|
||||||
|
} from 'ionicons/icons';
|
||||||
import {
|
import {
|
||||||
startBackgroundGeolocation,
|
startBackgroundGeolocation,
|
||||||
stopBackgroundGeolocation,
|
stopBackgroundGeolocation,
|
||||||
} from '../../lib/background-geolocation';
|
} from '../../lib/background-geolocation';
|
||||||
|
import { deleteCurrent, saveCurrent } from '../../db/gpx';
|
||||||
|
|
||||||
const GpxRecord: React.FC<{}> = () => {
|
const GpxRecord: React.FC<{}> = () => {
|
||||||
const db = useDB();
|
const db = useDB();
|
||||||
|
@ -18,24 +33,152 @@ const GpxRecord: React.FC<{}> = () => {
|
||||||
|
|
||||||
const [watcher_id, setWatcher_id] = useState();
|
const [watcher_id, setWatcher_id] = useState();
|
||||||
|
|
||||||
const toggleIsRecording = () => {
|
const gpxes = useFind({
|
||||||
if (isRecording) {
|
selector: {
|
||||||
stopBackgroundGeolocation(watcher_id);
|
type: 'gpx',
|
||||||
} else {
|
subtype: 'current',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasCurrentTrack = gpxes.length > 0;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`GpxRecord, hasCurrentTrack:${hasCurrentTrack}, gpxes: ${JSON.stringify(
|
||||||
|
gpxes
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const modal = useRef<HTMLIonModalElement>(null);
|
||||||
|
|
||||||
|
const dismiss = () => {
|
||||||
|
modal.current?.dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
const startRecording = () => {
|
||||||
startBackgroundGeolocation(db).then((result) => {
|
startBackgroundGeolocation(db).then((result) => {
|
||||||
setWatcher_id(result);
|
setWatcher_id(result);
|
||||||
});
|
});
|
||||||
|
setIsRecording(true);
|
||||||
|
dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
const pauseRecording = () => {
|
||||||
|
if (isRecording) {
|
||||||
|
stopBackgroundGeolocation(watcher_id);
|
||||||
}
|
}
|
||||||
setIsRecording(!isRecording);
|
setIsRecording(false);
|
||||||
|
dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopRecording = () => {
|
||||||
|
saveCurrent(db);
|
||||||
|
pauseRecording();
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteRecording = () => {
|
||||||
|
deleteCurrent(db);
|
||||||
|
pauseRecording();
|
||||||
|
};
|
||||||
|
|
||||||
|
const enterAnimation = (baseEl: HTMLElement) => {
|
||||||
|
const root = baseEl.shadowRoot;
|
||||||
|
|
||||||
|
const backdropAnimation = createAnimation()
|
||||||
|
.addElement(root?.querySelector('ion-backdrop')!)
|
||||||
|
.fromTo('opacity', '0.01', 'var(--backdrop-opacity)');
|
||||||
|
|
||||||
|
const wrapperAnimation = createAnimation()
|
||||||
|
.addElement(root?.querySelector('.modal-wrapper')!)
|
||||||
|
.keyframes([
|
||||||
|
{ offset: 0, opacity: '0', transform: 'scale(0)' },
|
||||||
|
{ offset: 1, opacity: '0.99', transform: 'scale(1)' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return createAnimation()
|
||||||
|
.addElement(baseEl)
|
||||||
|
.easing('ease-out')
|
||||||
|
.duration(500)
|
||||||
|
.addAnimation([backdropAnimation, wrapperAnimation]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const leaveAnimation = (baseEl: HTMLElement) => {
|
||||||
|
return enterAnimation(baseEl).direction('reverse');
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IonButton onClick={toggleIsRecording}>
|
<Fragment>
|
||||||
|
<IonButton id='open-RecordDialog'>
|
||||||
{isRecording && (
|
{isRecording && (
|
||||||
<IonIcon slot='icon-only' icon={recording} style={{ color: 'red' }} />
|
<IonIcon slot='icon-only' icon={recording} style={{ color: 'red' }} />
|
||||||
)}
|
)}
|
||||||
{!isRecording && <IonIcon slot='icon-only' icon={recordingOutline} />}
|
{!isRecording && <IonIcon slot='icon-only' icon={recordingOutline} />}
|
||||||
</IonButton>
|
</IonButton>
|
||||||
|
<IonModal
|
||||||
|
ref={modal}
|
||||||
|
trigger='open-RecordDialog'
|
||||||
|
enterAnimation={enterAnimation}
|
||||||
|
leaveAnimation={leaveAnimation}
|
||||||
|
>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle>Track recording</IonTitle>
|
||||||
|
<IonButtons slot='end'>
|
||||||
|
<IonButton onClick={() => dismiss()}>Close</IonButton>
|
||||||
|
</IonButtons>
|
||||||
|
</IonToolbar>
|
||||||
|
<IonContent>
|
||||||
|
{!isRecording && (
|
||||||
|
<IonButton
|
||||||
|
expand='block'
|
||||||
|
color='primary'
|
||||||
|
size='large'
|
||||||
|
onClick={startRecording}
|
||||||
|
>
|
||||||
|
<IonIcon slot='start' icon={recording}></IonIcon>
|
||||||
|
{hasCurrentTrack ? (
|
||||||
|
<span>Resume recording</span>
|
||||||
|
) : (
|
||||||
|
<span>Start recording</span>
|
||||||
|
)}
|
||||||
|
</IonButton>
|
||||||
|
)}
|
||||||
|
{isRecording && (
|
||||||
|
<IonButton
|
||||||
|
expand='block'
|
||||||
|
color='primary'
|
||||||
|
size='large'
|
||||||
|
onClick={pauseRecording}
|
||||||
|
>
|
||||||
|
<IonIcon slot='start' icon={pauseCircle}></IonIcon>Pause
|
||||||
|
</IonButton>
|
||||||
|
)}
|
||||||
|
{hasCurrentTrack && (
|
||||||
|
<>
|
||||||
|
<IonButton
|
||||||
|
expand='block'
|
||||||
|
color='danger'
|
||||||
|
size='large'
|
||||||
|
onClick={stopRecording}
|
||||||
|
>
|
||||||
|
<IonIcon slot='start' icon={stop}></IonIcon>Stop recording
|
||||||
|
<br />
|
||||||
|
(and save track)
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand='block'
|
||||||
|
color='danger'
|
||||||
|
size='large'
|
||||||
|
onClick={deleteRecording}
|
||||||
|
>
|
||||||
|
<IonIcon slot='start' icon={closeCircle}></IonIcon>Cancel
|
||||||
|
recording
|
||||||
|
<br />
|
||||||
|
(and clear track)
|
||||||
|
</IonButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</IonContent>
|
||||||
|
</IonModal>
|
||||||
|
</Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { initDb } from '.';
|
import { initDb } from '.';
|
||||||
import PouchDB from 'pouchdb';
|
import PouchDB from 'pouchdb';
|
||||||
import { appendTrkpt } from './gpx';
|
import { appendTrkpt, deleteCurrent, saveCurrent } from './gpx';
|
||||||
|
|
||||||
import PouchDBFind from 'pouchdb-find';
|
import PouchDBFind from 'pouchdb-find';
|
||||||
import { mkdtempSync, rmdirSync } from 'fs';
|
import { mkdtempSync, rmdirSync } from 'fs';
|
||||||
|
@ -48,3 +48,54 @@ describe('Checking that trkpts are beeing inserted', () => {
|
||||||
expect(docs.length).toBe(3);
|
expect(docs.length).toBe(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Checking that saveCurrent() is working as expected', () => {
|
||||||
|
test(', that we still have two documents after saving.', async () => {
|
||||||
|
await appendTrkpt(db, {});
|
||||||
|
await saveCurrent(db);
|
||||||
|
const results = await db.find({
|
||||||
|
selector: {},
|
||||||
|
});
|
||||||
|
const docs = results.docs;
|
||||||
|
// console.log(`docs: ${JSON.stringify(docs)}`);
|
||||||
|
expect(docs.length).toBe(2);
|
||||||
|
});
|
||||||
|
test("and that we don't have current tracks after saving.", async () => {
|
||||||
|
await appendTrkpt(db, {});
|
||||||
|
await saveCurrent(db);
|
||||||
|
const results = await db.find({
|
||||||
|
selector: {
|
||||||
|
type: 'gpx',
|
||||||
|
subtype: 'current',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const docs = results.docs;
|
||||||
|
// console.log(`docs: ${JSON.stringify(docs)}`);
|
||||||
|
expect(docs.length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Checking that deleteCurrent() is working as expected', () => {
|
||||||
|
test(', that we have no more documents after deleting.', async () => {
|
||||||
|
await appendTrkpt(db, { time: '' });
|
||||||
|
await deleteCurrent(db);
|
||||||
|
const results = await db.find({
|
||||||
|
selector: {},
|
||||||
|
});
|
||||||
|
const docs = results.docs;
|
||||||
|
// console.log(`docs: ${JSON.stringify(docs)}`);
|
||||||
|
expect(docs.length).toBe(0);
|
||||||
|
});
|
||||||
|
test(', that we have two documents from a saved track after deleting the current one.', async () => {
|
||||||
|
await appendTrkpt(db, { time: '' });
|
||||||
|
await saveCurrent(db);
|
||||||
|
await appendTrkpt(db, { time: '' });
|
||||||
|
await deleteCurrent(db);
|
||||||
|
const results = await db.find({
|
||||||
|
selector: {},
|
||||||
|
});
|
||||||
|
const docs = results.docs;
|
||||||
|
// console.log(`docs: ${JSON.stringify(docs)}`);
|
||||||
|
expect(docs.length).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -93,8 +93,6 @@ const initialGpx = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const appendTrkpt = async (db: any, trkpt: any) => {
|
export const appendTrkpt = async (db: any, trkpt: any) => {
|
||||||
|
|
||||||
|
|
||||||
const currents = await db.find({
|
const currents = await db.find({
|
||||||
selector: {
|
selector: {
|
||||||
type: 'gpx',
|
type: 'gpx',
|
||||||
|
@ -118,3 +116,49 @@ export const appendTrkpt = async (db: any, trkpt: any) => {
|
||||||
await db.post(docPoint);
|
await db.post(docPoint);
|
||||||
console.log(JSON.stringify(docPoint));
|
console.log(JSON.stringify(docPoint));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const saveCurrent = async (db: any) => {
|
||||||
|
const currents = await db.find({
|
||||||
|
selector: {
|
||||||
|
type: 'gpx',
|
||||||
|
subtype: 'current',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log(`saveCurrent - db.find() : ${JSON.stringify(currents)}`);
|
||||||
|
if (currents.docs.length > 0) {
|
||||||
|
const doc = currents.docs[0];
|
||||||
|
doc.subtype = 'other';
|
||||||
|
await db.put(doc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteCurrent = async (db: any) => {
|
||||||
|
const currents = await db.find({
|
||||||
|
selector: {
|
||||||
|
type: 'gpx',
|
||||||
|
subtype: 'current',
|
||||||
|
},
|
||||||
|
fields: ['_id', '_rev'],
|
||||||
|
});
|
||||||
|
console.log(`deleteCurrent - db.find(gpx) : ${JSON.stringify(currents)}`);
|
||||||
|
const docs: { _id: string; _rev: string }[] = currents.docs;
|
||||||
|
for (let i = 0; i < docs.length; i++) {
|
||||||
|
console.log(`Deleting document ${JSON.stringify(docs[i])}`);
|
||||||
|
await db.put({ _deleted: true, ...docs[i] });
|
||||||
|
console.log(`done, id: ${docs[i]._id}`);
|
||||||
|
const currentTrkpts = await db.find({
|
||||||
|
selector: {
|
||||||
|
type: 'trkpt',
|
||||||
|
gpx: docs[i]._id,
|
||||||
|
},
|
||||||
|
fields: ['_id', '_rev', 'type'],
|
||||||
|
});
|
||||||
|
console.log(
|
||||||
|
`deleteCurrent - db.find(trkpts) : ${JSON.stringify(currentTrkpts)}`
|
||||||
|
);
|
||||||
|
const trkpts: { _id: string; _rev: string }[] = currentTrkpts.docs;
|
||||||
|
for (let j = 0; j < trkpts.length; j++) {
|
||||||
|
await db.put({ _deleted: true, ...trkpts[j] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -53,9 +53,9 @@ export const initDb = async (db: any, setDbReady: any) => {
|
||||||
for (var index of existingIndexes) {
|
for (var index of existingIndexes) {
|
||||||
if (index.type === 'json') {
|
if (index.type === 'json') {
|
||||||
// Non system indexes
|
// Non system indexes
|
||||||
console.log(`Checking existing index :${JSON.stringify(index)}`);
|
// console.log(`Checking existing index :${JSON.stringify(index)}`);
|
||||||
if (!findIndex(requiredIndexes, index)) {
|
if (!findIndex(requiredIndexes, index)) {
|
||||||
console.log(`db.deleteIndex(${JSON.stringify(index)})`);
|
// console.log(`db.deleteIndex(${JSON.stringify(index)})`);
|
||||||
await db.deleteIndex(index);
|
await db.deleteIndex(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,14 +63,14 @@ export const initDb = async (db: any, setDbReady: any) => {
|
||||||
|
|
||||||
for (var index of requiredIndexes) {
|
for (var index of requiredIndexes) {
|
||||||
if (!findIndex(existingIndexes, index)) {
|
if (!findIndex(existingIndexes, index)) {
|
||||||
console.log(`db.createIndex(${JSON.stringify(index)})`);
|
// console.log(`db.createIndex(${JSON.stringify(index)})`);
|
||||||
await db.createIndex({ name: index.name, ...index.def });
|
await db.createIndex({ name: index.name, ...index.def });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setDbReady(true);
|
setDbReady(true);
|
||||||
|
|
||||||
const indexes = await db.getIndexes();
|
/* const indexes = await db.getIndexes();
|
||||||
console.log(`indexes: ${JSON.stringify(indexes)}`);
|
console.log(`indexes: ${JSON.stringify(indexes)}`);
|
||||||
|
|
||||||
const explain1 = await db.explain({
|
const explain1 = await db.explain({
|
||||||
|
@ -90,4 +90,5 @@ export const initDb = async (db: any, setDbReady: any) => {
|
||||||
// use_index: 'type-trkpt-gpx-time',
|
// use_index: 'type-trkpt-gpx-time',
|
||||||
});
|
});
|
||||||
console.log(`explain2: ${JSON.stringify(explain2)}`);
|
console.log(`explain2: ${JSON.stringify(explain2)}`);
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue