From 3235d9ae7015b9b8c2e526c334fbe9fb4bea1825 Mon Sep 17 00:00:00 2001 From: evlist Date: Tue, 27 Sep 2022 21:53:52 +0200 Subject: [PATCH] Basic dialog to start/pause/stop and clear track recording. --- src/components/map/gpx-record.tsx | 177 +++++++++++++++++++++++++++--- src/db/gpx.test.ts | 55 +++++++++- src/db/gpx.ts | 48 +++++++- src/db/index.ts | 9 +- 4 files changed, 264 insertions(+), 25 deletions(-) diff --git a/src/components/map/gpx-record.tsx b/src/components/map/gpx-record.tsx index f172970..895b5bb 100644 --- a/src/components/map/gpx-record.tsx +++ b/src/components/map/gpx-record.tsx @@ -1,15 +1,30 @@ -import React, { useState } from 'react'; - -import { useDB } from 'react-pouchdb'; +import React, { Fragment, useRef, useState } from 'react'; +import { useDB, useFind } from 'react-pouchdb'; import '../../theme/get-location.css'; -import { IonButton, IonIcon } from '@ionic/react'; -import { recordingOutline, recording } from 'ionicons/icons'; +import { + createAnimation, + IonButton, + IonButtons, + IonContent, + IonIcon, + IonModal, + IonTitle, + IonToolbar, +} from '@ionic/react'; +import { + recordingOutline, + recording, + closeCircle, + pauseCircle, + stop, +} from 'ionicons/icons'; import { startBackgroundGeolocation, stopBackgroundGeolocation, } from '../../lib/background-geolocation'; +import { deleteCurrent, saveCurrent } from '../../db/gpx'; const GpxRecord: React.FC<{}> = () => { const db = useDB(); @@ -18,24 +33,152 @@ const GpxRecord: React.FC<{}> = () => { const [watcher_id, setWatcher_id] = useState(); - const toggleIsRecording = () => { + const gpxes = useFind({ + selector: { + type: 'gpx', + subtype: 'current', + }, + }); + + const hasCurrentTrack = gpxes.length > 0; + + console.log( + `GpxRecord, hasCurrentTrack:${hasCurrentTrack}, gpxes: ${JSON.stringify( + gpxes + )}` + ); + + const modal = useRef(null); + + const dismiss = () => { + modal.current?.dismiss(); + }; + + const startRecording = () => { + startBackgroundGeolocation(db).then((result) => { + setWatcher_id(result); + }); + setIsRecording(true); + dismiss(); + }; + + const pauseRecording = () => { if (isRecording) { stopBackgroundGeolocation(watcher_id); - } else { - startBackgroundGeolocation(db).then((result) => { - setWatcher_id(result); - }); } - 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 ( - - {isRecording && ( - - )} - {!isRecording && } - + + + {isRecording && ( + + )} + {!isRecording && } + + + + Track recording + + dismiss()}>Close + + + + {!isRecording && ( + + + {hasCurrentTrack ? ( + Resume recording + ) : ( + Start recording + )} + + )} + {isRecording && ( + + Pause + + )} + {hasCurrentTrack && ( + <> + + Stop recording +
+ (and save track) +
+ + Cancel + recording +
+ (and clear track) +
+ + )} +
+
+
); }; diff --git a/src/db/gpx.test.ts b/src/db/gpx.test.ts index 0f90ce9..23cca91 100644 --- a/src/db/gpx.test.ts +++ b/src/db/gpx.test.ts @@ -1,6 +1,6 @@ import { initDb } from '.'; import PouchDB from 'pouchdb'; -import { appendTrkpt } from './gpx'; +import { appendTrkpt, deleteCurrent, saveCurrent } from './gpx'; import PouchDBFind from 'pouchdb-find'; import { mkdtempSync, rmdirSync } from 'fs'; @@ -27,7 +27,7 @@ beforeEach(async () => { }); afterEach(async () => { -// await db.close(); + // await db.close(); await db.destroy(); }); @@ -48,3 +48,54 @@ describe('Checking that trkpts are beeing inserted', () => { 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); + }); +}); diff --git a/src/db/gpx.ts b/src/db/gpx.ts index 34f3fd1..cf2e00a 100644 --- a/src/db/gpx.ts +++ b/src/db/gpx.ts @@ -93,8 +93,6 @@ const initialGpx = { }; export const appendTrkpt = async (db: any, trkpt: any) => { - - const currents = await db.find({ selector: { type: 'gpx', @@ -118,3 +116,49 @@ export const appendTrkpt = async (db: any, trkpt: any) => { await db.post(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] }); + } + } +}; diff --git a/src/db/index.ts b/src/db/index.ts index 52d949c..f0a171d 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -53,9 +53,9 @@ export const initDb = async (db: any, setDbReady: any) => { for (var index of existingIndexes) { if (index.type === 'json') { // Non system indexes - console.log(`Checking existing index :${JSON.stringify(index)}`); + // console.log(`Checking existing index :${JSON.stringify(index)}`); if (!findIndex(requiredIndexes, index)) { - console.log(`db.deleteIndex(${JSON.stringify(index)})`); + // console.log(`db.deleteIndex(${JSON.stringify(index)})`); await db.deleteIndex(index); } } @@ -63,14 +63,14 @@ export const initDb = async (db: any, setDbReady: any) => { for (var index of requiredIndexes) { 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 }); } } setDbReady(true); - const indexes = await db.getIndexes(); + /* const indexes = await db.getIndexes(); console.log(`indexes: ${JSON.stringify(indexes)}`); const explain1 = await db.explain({ @@ -90,4 +90,5 @@ export const initDb = async (db: any, setDbReady: any) => { // use_index: 'type-trkpt-gpx-time', }); console.log(`explain2: ${JSON.stringify(explain2)}`); + */ };