Creating a mechanism to store settings both in the database and in redux.
This commit is contained in:
1 parent
07edc22d31
commit
c0015a7cfa
10 files changed
+272
-18
No files matched your search
@@ -25,10 +25,9 @@ import {
|
||||
} from '../../lib/background-geolocation';
|
||||
import { appendTrkpt, deleteCurrent, saveCurrent } from '../../db/gpx';
|
||||
import { enterAnimation, leaveAnimation } from '../../lib/animation';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { mapActions } from '../../store/map';
|
||||
|
||||
const MIN_TIME_BETWEEN_LOCATIONS = 15 * 1000;
|
||||
import { SettingsState } from '../../store/settings';
|
||||
|
||||
declare global {
|
||||
var $lastValidLocationTime: number;
|
||||
@@ -41,6 +40,10 @@ const GpxRecord: React.FC<{}> = () => {
|
||||
|
||||
const [watcher_id, setWatcher_id] = useState();
|
||||
|
||||
const geolocationsSettingsState = useSelector(
|
||||
(state: { settings: SettingsState }) => state.settings.geolocation
|
||||
);
|
||||
|
||||
const gpxes = useFind({
|
||||
selector: {
|
||||
type: 'gpx',
|
||||
@@ -72,7 +75,7 @@ const GpxRecord: React.FC<{}> = () => {
|
||||
);
|
||||
if (
|
||||
location.time - globalThis.$lastValidLocationTime >
|
||||
MIN_TIME_BETWEEN_LOCATIONS
|
||||
geolocationsSettingsState.minTimeInterval
|
||||
) {
|
||||
globalThis.$lastValidLocationTime = location.time;
|
||||
appendTrkpt(db, {
|
||||
@@ -98,7 +101,10 @@ const GpxRecord: React.FC<{}> = () => {
|
||||
|
||||
const startRecording = () => {
|
||||
globalThis.$lastValidLocationTime = 0;
|
||||
startBackgroundGeolocation(newLocationHandler).then((result) => {
|
||||
startBackgroundGeolocation(
|
||||
newLocationHandler,
|
||||
geolocationsSettingsState.minDistance
|
||||
).then((result) => {
|
||||
setWatcher_id(result);
|
||||
});
|
||||
setIsRecording(true);
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
import React, { Fragment, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useDB } from 'react-pouchdb';
|
||||
|
||||
import {
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonContent,
|
||||
IonIcon,
|
||||
IonInput,
|
||||
IonItem,
|
||||
IonLabel,
|
||||
IonList,
|
||||
IonListHeader,
|
||||
IonModal,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
} from '@ionic/react';
|
||||
import { options, text } from 'ionicons/icons';
|
||||
import { enterAnimation, leaveAnimation } from '../../lib/animation';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { settingsActions, SettingsState } from '../../store/settings';
|
||||
import uri from '../../lib/ids';
|
||||
import _ from 'lodash';
|
||||
|
||||
const Settings: React.FC<{}> = () => {
|
||||
const dispatch = useDispatch();
|
||||
const db = useDB();
|
||||
|
||||
useEffect(() => {
|
||||
const initFromDb = async () => {
|
||||
try {
|
||||
const settingsFromDb = await db.get(uri('settings', {}));
|
||||
console.log(
|
||||
`settingsFromDb: ${JSON.stringify(settingsFromDb.settings)}`
|
||||
);
|
||||
dispatch(settingsActions.saveSettings(settingsFromDb.settings));
|
||||
} catch {}
|
||||
};
|
||||
initFromDb();
|
||||
}, []);
|
||||
|
||||
const settingsState = useSelector(
|
||||
(state: { settings: SettingsState }) => state.settings
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!settingsState.default) {
|
||||
const settingsFromRedux = async () => {
|
||||
const id = uri('settings', {});
|
||||
var settingsFromDb;
|
||||
try {
|
||||
settingsFromDb = await db.get(id);
|
||||
} catch (error) {
|
||||
console.log(
|
||||
`Error getting settings from db: ${JSON.stringify(error)}`
|
||||
);
|
||||
settingsFromDb = { _id: id, settings: {} };
|
||||
}
|
||||
if (!_.isEqual(settingsState, settingsFromDb.settings)) {
|
||||
console.log(`settingsFromRedux: ${JSON.stringify(settingsState)}`);
|
||||
settingsFromDb.settings = settingsState;
|
||||
db.put(settingsFromDb);
|
||||
}
|
||||
};
|
||||
settingsFromRedux();
|
||||
}
|
||||
}, [settingsState]);
|
||||
|
||||
const pseudo = useRef<HTMLIonInputElement>(null);
|
||||
const minTimeInterval = useRef<HTMLIonInputElement>(null);
|
||||
const minDistance = useRef<HTMLIonInputElement>(null);
|
||||
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
|
||||
const dismiss = () => {
|
||||
modal.current?.dismiss();
|
||||
};
|
||||
|
||||
const save = () => {
|
||||
dispatch(
|
||||
settingsActions.saveSettings({
|
||||
user: {
|
||||
pseudo: pseudo.current?.value,
|
||||
},
|
||||
geolocation: {
|
||||
minTimeInterval: minTimeInterval.current?.value,
|
||||
minDistance: minDistance.current?.value,
|
||||
},
|
||||
})
|
||||
);
|
||||
dismiss();
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<IonButton id='open-SettingsDialog'>
|
||||
<IonIcon slot='icon-only' icon={options} />
|
||||
</IonButton>
|
||||
<IonModal
|
||||
ref={modal}
|
||||
trigger='open-SettingsDialog'
|
||||
enterAnimation={enterAnimation}
|
||||
leaveAnimation={leaveAnimation}
|
||||
>
|
||||
<IonToolbar>
|
||||
<IonTitle>Settings</IonTitle>
|
||||
<IonButtons slot='end'>
|
||||
<IonButton onClick={() => dismiss()}>Close</IonButton>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
<IonContent>
|
||||
<IonList lines='full' class='ion-no-margin'>
|
||||
<IonListHeader lines='full'>
|
||||
<IonLabel>User</IonLabel>
|
||||
</IonListHeader>
|
||||
<IonItem>
|
||||
<IonLabel>Pseudo: </IonLabel>
|
||||
<IonInput
|
||||
ref={pseudo}
|
||||
value={settingsState.user.pseudo}
|
||||
autocomplete='nickname'
|
||||
></IonInput>
|
||||
</IonItem>
|
||||
</IonList>
|
||||
<IonList lines='full' class='ion-no-margin'>
|
||||
<IonListHeader lines='full'>
|
||||
<IonLabel>Geolocation</IonLabel>
|
||||
</IonListHeader>
|
||||
<IonItem>
|
||||
<IonLabel>Minimal time interval (ms): </IonLabel>
|
||||
<IonInput
|
||||
value={settingsState.geolocation.minTimeInterval}
|
||||
ref={minTimeInterval}
|
||||
inputMode='numeric'
|
||||
type='number'
|
||||
></IonInput>
|
||||
</IonItem>
|
||||
<IonItem>
|
||||
<IonLabel>Minimal distance (m): </IonLabel>
|
||||
<IonInput
|
||||
value={settingsState.geolocation.minDistance}
|
||||
ref={minDistance}
|
||||
inputMode='numeric'
|
||||
type='number'
|
||||
></IonInput>
|
||||
</IonItem>
|
||||
</IonList>
|
||||
<IonItem>
|
||||
<IonToolbar class='secondary'>
|
||||
<IonButtons slot='secondary'>
|
||||
<IonButton
|
||||
shape='round'
|
||||
fill='solid'
|
||||
color='primary'
|
||||
onClick={() => save()}
|
||||
>
|
||||
Save
|
||||
</IonButton>
|
||||
<IonButton
|
||||
shape='round'
|
||||
fill='outline'
|
||||
color='primary'
|
||||
onClick={() => dismiss()}
|
||||
>
|
||||
Cancel
|
||||
</IonButton>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonItem>
|
||||
</IonContent>
|
||||
</IonModal>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
@@ -25,6 +25,7 @@ import { initDb } from '../../db';
|
||||
import TileServerChooserButton from './TileServerChooserButton';
|
||||
import TileServerChooserDialog from './TileServerChooserDialog';
|
||||
import TrackBrowser from './TracksBrowser';
|
||||
import Settings from './Settings';
|
||||
|
||||
const Map: react.FC<{}> = (props: {}) => {
|
||||
const dispatch = useDispatch();
|
||||
@@ -68,6 +69,7 @@ const Map: react.FC<{}> = (props: {}) => {
|
||||
<TrackBrowser/>
|
||||
<GpxRecord />
|
||||
<TileServerChooserButton />
|
||||
<Settings />
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
Reference in new issue
Block a user