extensive changes
This commit is contained in:
@@ -106,12 +106,12 @@ export default defineConfig((/* ctx */) => {
|
|||||||
proxy: {
|
proxy: {
|
||||||
// proxy all requests starting with /api to jsonplaceholder
|
// proxy all requests starting with /api to jsonplaceholder
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://localhost:8000',
|
target: 'http://localhost:49151',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||||
},
|
},
|
||||||
'/socket.io': {
|
'/socket.io': {
|
||||||
target: 'http://localhost:8000', // Your backend WebSocket server
|
target: 'http://localhost:49151', // Your backend WebSocket server
|
||||||
secure: false, // Set to true if using wss://
|
secure: false, // Set to true if using wss://
|
||||||
ws: true, // Enable WebSocket proxying
|
ws: true, // Enable WebSocket proxying
|
||||||
rewriteWsOrigin: true,
|
rewriteWsOrigin: true,
|
||||||
@@ -141,7 +141,7 @@ export default defineConfig((/* ctx */) => {
|
|||||||
},
|
},
|
||||||
// animations: 'all', // --- includes all animations
|
// animations: 'all', // --- includes all animations
|
||||||
// https://v2.quasar.dev/options/animations
|
// https://v2.quasar.dev/options/animations
|
||||||
animations: [],
|
animations: ['slideInLeft', 'slideOutLeft', 'slideOutRight'],
|
||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#sourcefiles
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#sourcefiles
|
||||||
// sourceFiles: {
|
// sourceFiles: {
|
||||||
|
|||||||
@@ -1,84 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<div style="display: none"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch, onMounted, onBeforeUnmount } from 'vue';
|
import {
|
||||||
import 'leaflet-routing-machine/dist/leaflet-routing-machine.css';
|
ref,
|
||||||
import L from 'leaflet';
|
markRaw,
|
||||||
|
inject,
|
||||||
|
nextTick,
|
||||||
|
onMounted,
|
||||||
|
onBeforeUnmount,
|
||||||
|
useAttrs,
|
||||||
|
defineEmits,
|
||||||
|
} from 'vue';
|
||||||
|
|
||||||
|
import { routingControlProps, setupRoutingControl } from 'functions/routingControl';
|
||||||
|
import { Utilities, InjectionKeys } from '@vue-leaflet/vue-leaflet';
|
||||||
|
|
||||||
|
import 'leaflet';
|
||||||
import 'leaflet-routing-machine';
|
import 'leaflet-routing-machine';
|
||||||
import 'leaflet-routing-machine/dist/leaflet-routing-machine.css';
|
import 'leaflet-routing-machine/dist/leaflet-routing-machine.css';
|
||||||
import type { IRouter, IGeocoder, LineOptions } from 'leaflet-routing-machine';
|
|
||||||
|
|
||||||
// Props
|
import type L from 'leaflet';
|
||||||
const props = defineProps<{
|
|
||||||
mapObject?: any;
|
// ---- Emits ----
|
||||||
visible?: boolean;
|
const emit = defineEmits<{
|
||||||
waypoints: any[];
|
(e: 'ready', value: L.Routing.Control): void;
|
||||||
router?: IRouter;
|
|
||||||
plan?: L.Routing.Plan;
|
|
||||||
geocoder?: IGeocoder;
|
|
||||||
fitSelectedRoutes?: string | boolean;
|
|
||||||
lineOptions?: LineOptions;
|
|
||||||
routeLine?: Function;
|
|
||||||
autoRoute?: boolean;
|
|
||||||
routeWhileDragging?: boolean;
|
|
||||||
routeDragInterval?: number;
|
|
||||||
waypointMode?: string;
|
|
||||||
useZoomParameter?: boolean;
|
|
||||||
showAlternatives?: boolean;
|
|
||||||
altLineOptions?: LineOptions;
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// Defaults
|
// ---- Props ----
|
||||||
const visible = props.visible ?? true;
|
const props = defineProps(routingControlProps);
|
||||||
const fitSelectedRoutes = props.fitSelectedRoutes ?? 'smart';
|
|
||||||
const autoRoute = props.autoRoute ?? true;
|
|
||||||
const routeWhileDragging = props.routeWhileDragging ?? false;
|
|
||||||
const routeDragInterval = props.routeDragInterval ?? 500;
|
|
||||||
const waypointMode = props.waypointMode ?? 'connect';
|
|
||||||
const useZoomParameter = props.useZoomParameter ?? false;
|
|
||||||
const showAlternatives = props.showAlternatives ?? false;
|
|
||||||
|
|
||||||
// State
|
// ---- Attrs (for events) ----
|
||||||
const ready = ref(false);
|
const attrs = useAttrs();
|
||||||
const layer = ref<any>(null);
|
|
||||||
|
|
||||||
// Methods
|
// ---- Injections ----
|
||||||
function add() {
|
const { UseGlobalLeafletInjection, RegisterControlInjection } = InjectionKeys;
|
||||||
if (!props.mapObject) return;
|
const { WINDOW_OR_GLOBAL, assertInject, propsBinder, remapEvents } = Utilities;
|
||||||
|
|
||||||
const options = {
|
const useGlobalLeaflet = inject(UseGlobalLeafletInjection, false);
|
||||||
waypoints: props.waypoints,
|
const registerControl = assertInject(RegisterControlInjection);
|
||||||
fitSelectedRoutes,
|
|
||||||
autoRoute,
|
|
||||||
routeWhileDragging,
|
|
||||||
routeDragInterval,
|
|
||||||
waypointMode,
|
|
||||||
useZoomParameter,
|
|
||||||
showAlternatives,
|
|
||||||
};
|
|
||||||
console.log(L.Routing);
|
|
||||||
const routingLayer = L.Routing.control(options);
|
|
||||||
routingLayer.addTo(props.mapObject);
|
|
||||||
layer.value = routingLayer;
|
|
||||||
|
|
||||||
ready.value = true;
|
// ---- State ----
|
||||||
}
|
const leafletObject = ref<L.Routing.Control | null>(null);
|
||||||
|
|
||||||
// Watchers
|
// ---- Setup logic ----
|
||||||
watch(
|
const { options, methods } = setupRoutingControl(props);
|
||||||
() => props.mapObject,
|
|
||||||
(val) => {
|
|
||||||
if (!val) return;
|
|
||||||
add();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Lifecycle
|
onMounted(async () => {
|
||||||
onMounted(() => {
|
const { routing } = useGlobalLeaflet
|
||||||
add();
|
? (WINDOW_OR_GLOBAL as any).L
|
||||||
|
: await import('leaflet/dist/leaflet-src.esm');
|
||||||
|
|
||||||
|
const { listeners } = remapEvents(attrs);
|
||||||
|
|
||||||
|
leafletObject.value = markRaw(routing.control(options));
|
||||||
|
leafletObject.value.on(listeners);
|
||||||
|
|
||||||
|
propsBinder(methods, leafletObject.value, props);
|
||||||
|
registerControl({ leafletObject: leafletObject.value });
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
emit('ready', leafletObject.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (layer.value) {
|
if (leafletObject.value) {
|
||||||
layer.value.remove();
|
leafletObject.value.setWaypoints([]);
|
||||||
|
leafletObject.value.remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,64 +1,168 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="height: 600px; width: 800px; color: #000000">
|
<div class="q-pa-md">
|
||||||
<L-Map
|
<q-layout
|
||||||
@ready="onMapReady"
|
view="hHh Lpr fFf"
|
||||||
ref="mapRef"
|
container
|
||||||
:zoom="zoom"
|
style="height: 600px; width: 100vw"
|
||||||
:center="center"
|
class="rounded-borders"
|
||||||
style="height: 500px; width: 100%"
|
|
||||||
@click="updateMarker"
|
|
||||||
>
|
>
|
||||||
<L-Tile-Layer
|
<q-footer :class="$q.dark.isActive ? 'bg-primary' : 'bg-black'" style="height: 48px">
|
||||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
<q-toolbar>
|
||||||
layer-type="base"
|
<q-btn
|
||||||
name="OpenStreetMap"
|
class="q-mr-sm"
|
||||||
@click="updateMarker($event.latlng)"
|
dense
|
||||||
></L-Tile-Layer>
|
flat
|
||||||
<L-Marker :lat-lng="markerLatLng" @click="handleMarkerClick"></L-Marker>
|
icon="menu"
|
||||||
<L-Routing-Machine
|
round
|
||||||
@routingstart="debugRoutingEvent"
|
size="sm"
|
||||||
@routesfound="debugRoutingEvent"
|
@click="qLocDrawer = !qLocDrawer"
|
||||||
@routingerror="debugRoutingEvent"
|
/>
|
||||||
:waypoints="waypoints"
|
<q-btn-dropdown flat label="Zoom To" size="sm" stretch>
|
||||||
/>
|
<q-list>
|
||||||
</L-Map>
|
<q-item v-close-popup v-ripple clickable @click="zoomTo('fmLoc')">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>Find My Location</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item v-close-popup v-ripple clickable @click="zoomTo('simLoc')">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>Sim Location</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-btn-dropdown>
|
||||||
|
<q-btn label="Routing" @click="routeLayer = !routeLayer" size="sm" stretch />
|
||||||
|
</q-toolbar>
|
||||||
|
</q-footer>
|
||||||
|
<q-drawer
|
||||||
|
v-model="qLocDrawer"
|
||||||
|
show-if-above
|
||||||
|
mini-to-overlay
|
||||||
|
overlay
|
||||||
|
:width="300"
|
||||||
|
side="left"
|
||||||
|
:breakpoint="500"
|
||||||
|
:mini="miniState"
|
||||||
|
@mouseenter="miniState = false"
|
||||||
|
@mouseleave="miniState = true"
|
||||||
|
>
|
||||||
|
<q-scroll-area class="fit" :horizontal-thumb-style="{ opacity: 0 }">
|
||||||
|
<q-list padding>
|
||||||
|
<q-item-label header>Location Queue</q-item-label>
|
||||||
|
<q-separator />
|
||||||
|
<LocationMark
|
||||||
|
v-for="key in locationQueueOrder"
|
||||||
|
:key="key"
|
||||||
|
:loc_id="key"
|
||||||
|
:active="locationQueueData[key].loc_id === currentLocation.loc_id"
|
||||||
|
:start="locationQueueData[key].start"
|
||||||
|
:address="locationQueueData[key].address"
|
||||||
|
:latitude="locationQueueData[key].latitude"
|
||||||
|
:longitude="locationQueueData[key].longitude"
|
||||||
|
:end="locationQueueData[key].end"
|
||||||
|
@item-clicked="zoomToCoods"
|
||||||
|
/>
|
||||||
|
</q-list>
|
||||||
|
</q-scroll-area>
|
||||||
|
</q-drawer>
|
||||||
|
|
||||||
|
<q-page-container>
|
||||||
|
<q-page>
|
||||||
|
<div style="height: 560px; width: 90vw; color: #000000">
|
||||||
|
<L-Map
|
||||||
|
ref="mapRef"
|
||||||
|
:center="center"
|
||||||
|
:zoom="zoom"
|
||||||
|
style="height: 550px; width: 100%"
|
||||||
|
@click="updateMarker"
|
||||||
|
@ready="onMapReady"
|
||||||
|
>
|
||||||
|
<L-Tile-Layer
|
||||||
|
layer-type="base"
|
||||||
|
name="OpenStreetMap"
|
||||||
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
|
@click="updateMarker($event.latlng)"
|
||||||
|
></L-Tile-Layer>
|
||||||
|
<L-Layer-Group>
|
||||||
|
<L-Marker v-if="markerLatLng" :lat-lng="markerLatLng" @click="handleMarkerClick">
|
||||||
|
</L-Marker>
|
||||||
|
</L-Layer-Group>
|
||||||
|
<L-Layer-Group v-if="locationQueueOrder">
|
||||||
|
<L-Marker
|
||||||
|
v-for="locid in locationQueueOrder"
|
||||||
|
:key="locid"
|
||||||
|
:icon="getCustomIcon(locid)"
|
||||||
|
:lat-lng="[locationQueueData[locid].latitude, locationQueueData[locid].longitude]"
|
||||||
|
>
|
||||||
|
</L-Marker>
|
||||||
|
</L-Layer-Group>
|
||||||
|
<L-Layer-Group v-if="routeLayer">
|
||||||
|
<LRoutingMachine
|
||||||
|
v-bind="routingOptions"
|
||||||
|
@routingstart="debugRoutingEvent"
|
||||||
|
@routesfound="debugRoutingEvent"
|
||||||
|
@routingerror="debugRoutingEvent"
|
||||||
|
/>
|
||||||
|
</L-Layer-Group>
|
||||||
|
<L-Layer-Group v-if="findMyUpdate">
|
||||||
|
<L-Marker
|
||||||
|
v-if="findMyUpdate"
|
||||||
|
:icon="fmIcon"
|
||||||
|
:lat-lng="[findMyUpdate.latitude, findMyUpdate.longitude]"
|
||||||
|
></L-Marker>
|
||||||
|
<L-Circle
|
||||||
|
:fillOpacity="0.5"
|
||||||
|
:lat-lng="[findMyUpdate.latitude, findMyUpdate.longitude]"
|
||||||
|
:radius="findMyUpdate.horizontalAccuracy"
|
||||||
|
color="firebrick"
|
||||||
|
fillColor="indianred"
|
||||||
|
></L-Circle>
|
||||||
|
</L-Layer-Group>
|
||||||
|
</L-Map>
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
|
</q-page-container>
|
||||||
|
</q-layout>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts" setup>
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import { ref } from 'vue';
|
import { computed, onMounted, reactive, ref } from 'vue';
|
||||||
import { GeoSearchControl, OpenStreetMapProvider } from 'leaflet-geosearch';
|
import { GeoSearchControl, OpenStreetMapProvider } from 'leaflet-geosearch';
|
||||||
import LRoutingMachine from 'components/LRoutingMachine.vue';
|
import 'leaflet-routing-machine/dist/leaflet-routing-machine.css';
|
||||||
|
import { Icon, PinCirclePanel, PinStarPanel } from 'leaflet-extra-markers';
|
||||||
import 'leaflet-geosearch/dist/geosearch.css';
|
import 'leaflet-geosearch/dist/geosearch.css';
|
||||||
import 'leaflet/dist/leaflet.css';
|
import 'leaflet/dist/leaflet.css';
|
||||||
|
import LRoutingMachine from 'components/LRoutingMachine.vue';
|
||||||
|
import LocationMark from 'components/LocationMark.vue';
|
||||||
|
|
||||||
import type { coords, SearchControlProps } from 'src/types';
|
import type { coords, SearchControlProps } from 'src/types';
|
||||||
import type { Map, LeafletMouseEvent } from 'leaflet';
|
import type { LeafletMouseEvent, Map } from 'leaflet';
|
||||||
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useSocketioStore } from 'stores/socketio';
|
import { useSocketioStore } from 'stores/socketio';
|
||||||
import { useLeafletStore } from 'stores/leaflet';
|
import { useLeafletStore } from 'stores/leaflet';
|
||||||
|
|
||||||
import SetLocationDialog from 'components/SetLocationDialog.vue';
|
import SetLocationDialog from 'components/SetLocationDialog.vue';
|
||||||
import { LMap, LMarker, LTileLayer } from '@vue-leaflet/vue-leaflet';
|
import { LCircle, LLayerGroup, LMap, LMarker, LTileLayer } from '@vue-leaflet/vue-leaflet';
|
||||||
|
import { favorites } from 'constants/favorites';
|
||||||
const waypoints = [
|
|
||||||
[ 38.7436056, -9.2304153 ],
|
|
||||||
[ 38.7436056, -0.131281 ],
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
const leafletStore = useLeafletStore();
|
const leafletStore = useLeafletStore();
|
||||||
const socketStore = useSocketioStore();
|
const { zoom, center, markerLatLng, qLocDrawer } = storeToRefs(leafletStore);
|
||||||
const { zoom, center, markerLatLng } = storeToRefs(socketStore);
|
|
||||||
const $q = useQuasar();
|
|
||||||
const mapRef = ref(null);
|
|
||||||
const responseMessage = ref('');
|
|
||||||
|
|
||||||
const debugRoutingEvent = (event) => {
|
const socketStore = useSocketioStore();
|
||||||
console.log(`${event.type} event: `, event);
|
const { currentLocation, nextLocation, locationQueueData, locationQueueOrder, findMyUpdate } =
|
||||||
};
|
storeToRefs(socketStore);
|
||||||
|
|
||||||
|
const $q = useQuasar();
|
||||||
|
|
||||||
|
const mapRef = ref();
|
||||||
|
const responseMessage = ref('');
|
||||||
|
const routeStart = ref(null);
|
||||||
|
const routeEnd = ref(null);
|
||||||
|
const routeLayer = ref(false);
|
||||||
|
const miniState = ref(true);
|
||||||
|
|
||||||
const onMapReady = (map: Map) => {
|
const onMapReady = (map: Map) => {
|
||||||
const provider = new OpenStreetMapProvider();
|
const provider = new OpenStreetMapProvider();
|
||||||
@@ -81,6 +185,48 @@ const onMapReady = (map: Map) => {
|
|||||||
map.addControl(searchControl);
|
map.addControl(searchControl);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fmIcon = new Icon({
|
||||||
|
color: 'indianred',
|
||||||
|
accentColor: 'firebrick',
|
||||||
|
content: 'FM',
|
||||||
|
contentColor: 'white',
|
||||||
|
scale: 1,
|
||||||
|
svg: PinCirclePanel,
|
||||||
|
});
|
||||||
|
|
||||||
|
const getCustomIcon = (locid: string) => {
|
||||||
|
const locationIndex = locationQueueOrder.value.indexOf(locid);
|
||||||
|
if (currentLocation.value && currentLocation.value.loc_id === locid) {
|
||||||
|
return new Icon({
|
||||||
|
color: 'pink',
|
||||||
|
accentColor: 'black',
|
||||||
|
content: '*',
|
||||||
|
contentColor: 'black',
|
||||||
|
scale: 1.5,
|
||||||
|
svg: PinStarPanel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return new Icon({
|
||||||
|
color: 'blue',
|
||||||
|
accentColor: 'firebrick',
|
||||||
|
content: locationIndex.toString(),
|
||||||
|
contentColor: 'white',
|
||||||
|
scale: 1,
|
||||||
|
svg: PinCirclePanel,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const routingOptions = reactive({
|
||||||
|
waypoints: [
|
||||||
|
[40.910773020811, -73.891069806448],
|
||||||
|
[40.90930366920829, -73.87658695470259],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const debugRoutingEvent = (event) => {
|
||||||
|
console.log(`${event.type} event: `, event);
|
||||||
|
};
|
||||||
|
|
||||||
function updateMarker(event: LeafletMouseEvent) {
|
function updateMarker(event: LeafletMouseEvent) {
|
||||||
markerLatLng.value = [event.latlng.lat, event.latlng.lng];
|
markerLatLng.value = [event.latlng.lat, event.latlng.lng];
|
||||||
center.value = [event.latlng.lat, event.latlng.lng];
|
center.value = [event.latlng.lat, event.latlng.lng];
|
||||||
@@ -114,10 +260,17 @@ function handleMarkerClick(event: LeafletMouseEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setLocation(coords: coords, delay: number) {
|
function setLocation(coords: coords, delay: number) {
|
||||||
|
let notType: string = 'positive';
|
||||||
try {
|
try {
|
||||||
responseMessage.value = socketStore.simulationControl('add', delay, coords.lat, coords.lng);
|
const setCmdRsp = socketStore.simulationControl('add', delay, coords.lat, coords.lng);
|
||||||
$q.notify({ type: 'positive', message: responseMessage.value });
|
if (setCmdRsp.sts === 'error') {
|
||||||
|
notType = 'negative';
|
||||||
|
}
|
||||||
|
if (setCmdRsp.msg) {
|
||||||
|
responseMessage.value = setCmdRsp.msg;
|
||||||
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
notType = 'negative';
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
console.error('Error setting location:', error.message);
|
console.error('Error setting location:', error.message);
|
||||||
responseMessage.value = `Failed to set location: ${error.message}`;
|
responseMessage.value = `Failed to set location: ${error.message}`;
|
||||||
@@ -125,14 +278,65 @@ function setLocation(coords: coords, delay: number) {
|
|||||||
console.error('Error setting location:', error);
|
console.error('Error setting location:', error);
|
||||||
responseMessage.value = `Failed to set location: Unknown error`;
|
responseMessage.value = `Failed to set location: Unknown error`;
|
||||||
}
|
}
|
||||||
$q.notify({ type: 'negative', message: responseMessage.value });
|
} finally {
|
||||||
|
$q.notify({ type: notType, message: responseMessage.value });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zoomToCoods(arg: string) {
|
||||||
|
leafletStore.setCenter(
|
||||||
|
locationQueueData.value[arg].latitude,
|
||||||
|
locationQueueData.value[arg].longitude,
|
||||||
|
);
|
||||||
|
leafletStore.setZoom(50);
|
||||||
|
qLocDrawer.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoomTo(loc: string) {
|
||||||
|
switch (loc) {
|
||||||
|
case 'fmLoc':
|
||||||
|
if (findMyUpdate.value && findMyUpdate.value.latitude && findMyUpdate.value.longitude) {
|
||||||
|
leafletStore.setCenter(findMyUpdate.value.latitude, findMyUpdate.value.longitude);
|
||||||
|
}
|
||||||
|
$q.notify({ type: 'negative', message: 'Find My Location not available' });
|
||||||
|
break;
|
||||||
|
case 'simLoc':
|
||||||
|
if (
|
||||||
|
currentLocation.value &&
|
||||||
|
currentLocation.value.latitude &&
|
||||||
|
currentLocation.value.longitude
|
||||||
|
) {
|
||||||
|
leafletStore.setCenter(currentLocation.value.latitude, currentLocation.value.longitude);
|
||||||
|
}
|
||||||
|
$q.notify({ type: 'negative', message: 'Simulation Location not available' });
|
||||||
|
break;
|
||||||
|
case 'nextLoc':
|
||||||
|
if (nextLocation.value && nextLocation.value.latitude && nextLocation.value.longitude) {
|
||||||
|
leafletStore.setCenter(nextLocation.value.latitude, nextLocation.value.longitude);
|
||||||
|
}
|
||||||
|
$q.notify({ type: 'negative', message: 'Next Location not available' });
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$q.notify({ type: 'negative', message: 'Invalid location' });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (findMyUpdate.value && findMyUpdate.value.latitude && findMyUpdate.value.longitude) {
|
||||||
|
leafletStore.setCenter(findMyUpdate.value.latitude, findMyUpdate.value.longitude);
|
||||||
|
} else {
|
||||||
|
leafletStore.setCenter(favorites.home.coords.lat, favorites.home.coords.lng);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="sass">
|
||||||
.l-map {
|
.l-map
|
||||||
height: 100vh;
|
height: 100vh
|
||||||
width: 100vw;
|
width: 100vw
|
||||||
}
|
|
||||||
|
.q-item.q-router-link--active, .q-item--active
|
||||||
|
background-color: $accent
|
||||||
|
color: $primary
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
226
src/components/LocationMark.vue
Normal file
226
src/components/LocationMark.vue
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useSocketioStore } from 'stores/socketio';
|
||||||
|
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
||||||
|
|
||||||
|
const socketStore = useSocketioStore();
|
||||||
|
const { currentLocation, locationQueueOrder } = storeToRefs(socketStore);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
address: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
latitude: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
longitude: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: 'location_on',
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
delay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
active: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
loc_id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define custom events that this component can emit
|
||||||
|
const emit = defineEmits(['item-clicked']);
|
||||||
|
|
||||||
|
function itemClicked() {
|
||||||
|
const param1 = props.loc_id;
|
||||||
|
emit('item-clicked', param1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTime = ref(new Date());
|
||||||
|
let timerId: number;
|
||||||
|
|
||||||
|
const calculateDeltaT = computed(() => {
|
||||||
|
let delta = '';
|
||||||
|
if (props.active) {
|
||||||
|
delta = 'now';
|
||||||
|
} else if (props.end && props.end !== '') {
|
||||||
|
const pastTime: Date = new Date(props.end);
|
||||||
|
const nowMs: number = currentTime.value.getTime();
|
||||||
|
const pastMs: number = pastTime.getTime();
|
||||||
|
const diffMs: number = Math.abs(nowMs - pastMs);
|
||||||
|
const seconds: number = Math.floor(diffMs / 1000);
|
||||||
|
const minutes: number = Math.floor(seconds / 60);
|
||||||
|
const hours: number = Math.floor(minutes / 60);
|
||||||
|
const days: number = Math.floor(hours / 24);
|
||||||
|
if (days > 0) {
|
||||||
|
delta = `${days} day${days > 1 ? 's' : ''} ago`;
|
||||||
|
} else if (hours > 0) {
|
||||||
|
delta = `${hours} hour${hours > 1 ? 's' : ''} ago`;
|
||||||
|
} else if (minutes > 0) {
|
||||||
|
delta = `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
|
||||||
|
} else {
|
||||||
|
delta = `${seconds} second${seconds > 1 ? 's' : ''} ago`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const futureTime: Date = new Date(props.start);
|
||||||
|
const nowMs: number = currentTime.value.getTime();
|
||||||
|
const futureMs: number = futureTime.getTime();
|
||||||
|
const diffMs: number = Math.abs(nowMs - futureMs);
|
||||||
|
const seconds: number = Math.floor(diffMs / 1000);
|
||||||
|
const minutes: number = Math.floor(seconds / 60);
|
||||||
|
const hours: number = Math.floor(minutes / 60);
|
||||||
|
const days: number = Math.floor(hours / 24);
|
||||||
|
if (days > 0) {
|
||||||
|
delta = `in ${days} day${days > 1 ? 's' : ''}`;
|
||||||
|
} else if (hours > 0) {
|
||||||
|
delta = `in ${hours} hour${hours > 1 ? 's' : ''}`;
|
||||||
|
} else if (minutes > 0) {
|
||||||
|
delta = `in ${minutes} minute${minutes > 1 ? 's' : ''}`;
|
||||||
|
} else {
|
||||||
|
delta = `in ${seconds} second${seconds > 1 ? 's' : ''}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return delta;
|
||||||
|
});
|
||||||
|
|
||||||
|
const humanReadableDateTime = (iso: string) => {
|
||||||
|
return new Date(iso).toLocaleDateString('en-US', {
|
||||||
|
// year: 'numeric',
|
||||||
|
// month: 'long',
|
||||||
|
// day: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const stateAbbrevMap: Record<string, string> = {
|
||||||
|
Alabama: 'AL',
|
||||||
|
Alaska: 'AK',
|
||||||
|
Arizona: 'AZ',
|
||||||
|
Arkansas: 'AR',
|
||||||
|
California: 'CA',
|
||||||
|
Colorado: 'CO',
|
||||||
|
Connecticut: 'CT',
|
||||||
|
Delaware: 'DE',
|
||||||
|
Florida: 'FL',
|
||||||
|
Georgia: 'GA',
|
||||||
|
Hawaii: 'HI',
|
||||||
|
Idaho: 'ID',
|
||||||
|
Illinois: 'IL',
|
||||||
|
Indiana: 'IN',
|
||||||
|
Iowa: 'IA',
|
||||||
|
Kansas: 'KS',
|
||||||
|
Kentucky: 'KY',
|
||||||
|
Louisiana: 'LA',
|
||||||
|
Maine: 'ME',
|
||||||
|
Maryland: 'MD',
|
||||||
|
Massachusetts: 'MA',
|
||||||
|
Michigan: 'MI',
|
||||||
|
Minnesota: 'MN',
|
||||||
|
Mississippi: 'MS',
|
||||||
|
Missouri: 'MO',
|
||||||
|
Montana: 'MT',
|
||||||
|
Nebraska: 'NE',
|
||||||
|
Nevada: 'NV',
|
||||||
|
'New Hampshire': 'NH',
|
||||||
|
'New Jersey': 'NJ',
|
||||||
|
'New Mexico': 'NM',
|
||||||
|
'New York': 'NY',
|
||||||
|
'North Carolina': 'NC',
|
||||||
|
'North Dakota': 'ND',
|
||||||
|
Ohio: 'OH',
|
||||||
|
Oklahoma: 'OK',
|
||||||
|
Oregon: 'OR',
|
||||||
|
Pennsylvania: 'PA',
|
||||||
|
'Rhode Island': 'RI',
|
||||||
|
'South Carolina': 'SC',
|
||||||
|
'South Dakota': 'SD',
|
||||||
|
Tennessee: 'TN',
|
||||||
|
Texas: 'TX',
|
||||||
|
Utah: 'UT',
|
||||||
|
Vermont: 'VT',
|
||||||
|
Virginia: 'VA',
|
||||||
|
Washington: 'WA',
|
||||||
|
'West Virginia': 'WV',
|
||||||
|
Wisconsin: 'WI',
|
||||||
|
Wyoming: 'WY',
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatAddress(input: string): string {
|
||||||
|
const parts = input.split(',').map((p) => p.trim());
|
||||||
|
|
||||||
|
if (parts.length < 5) return input; // fallback safety
|
||||||
|
|
||||||
|
const streetNumber = parts[0];
|
||||||
|
const streetName = parts[1];
|
||||||
|
|
||||||
|
const zip = parts.at(-2) ?? '';
|
||||||
|
const stateFull = parts.at(-3) ?? '';
|
||||||
|
const cityRaw = parts.at(-5) ?? '';
|
||||||
|
|
||||||
|
const city = cityRaw.replace(/^City of\s+/i, '');
|
||||||
|
const state = stateAbbrevMap[stateFull] ?? stateFull;
|
||||||
|
|
||||||
|
return `${streetNumber} ${streetName}, ${city}, ${state} ${zip}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const update = () => {
|
||||||
|
currentTime.value = new Date();
|
||||||
|
timerId = requestAnimationFrame(update);
|
||||||
|
};
|
||||||
|
timerId = requestAnimationFrame(update);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
cancelAnimationFrame(timerId);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-item v-ripple clickable :active="active" @click="itemClicked">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label
|
||||||
|
>{{ formatAddress(address) }}
|
||||||
|
<q-tooltip> {{ latitude }}, {{ longitude }} </q-tooltip>
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-label caption lines="1" v-if="start">
|
||||||
|
start: {{ humanReadableDateTime(start) }}
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-label caption lines="1" v-if="end">
|
||||||
|
end: {{ humanReadableDateTime(end) }}
|
||||||
|
</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section side top>
|
||||||
|
<q-item-label caption lines="1">
|
||||||
|
{{ calculateDeltaT }}
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-section avatar class="q-pt-md">
|
||||||
|
<q-btn dense color="primary" round icon="location_on" class="q-ml-md">
|
||||||
|
<q-badge color="accent" floating>{{
|
||||||
|
active ? '*' : locationQueueOrder.indexOf(loc_id)
|
||||||
|
}}</q-badge>
|
||||||
|
</q-btn>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useLeafletStore } from 'stores/leaflet';
|
import { useLeafletStore } from 'stores/leaflet';
|
||||||
import type { Control, coords, CtrlAttr, CtrlAttrs } from 'components/models';
|
import type { coords, CtrlAttrs } from 'components/models';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { socket } from 'boot/socketio';
|
import { socket } from 'boot/socketio';
|
||||||
import ConfirmCommandDialog from 'components/ConfirmCommandDiaglog.vue';
|
import ConfirmCommandDialog from 'components/ConfirmCommandDiaglog.vue';
|
||||||
@@ -18,18 +18,16 @@ const leafletStore = useLeafletStore();
|
|||||||
const socketStore = useSocketioStore();
|
const socketStore = useSocketioStore();
|
||||||
const { center, markerLatLng } = storeToRefs(leafletStore);
|
const { center, markerLatLng } = storeToRefs(leafletStore);
|
||||||
|
|
||||||
|
const { simulationRunning, simulationState, simulationQueueLength, icloudMonitor, testMode } = storeToRefs(socketStore);
|
||||||
const { simulationRunning, simulationState, simulationQueueLength } = storeToRefs(socketStore);
|
|
||||||
|
|
||||||
const menuOpen = ref();
|
const menuOpen = ref();
|
||||||
|
|
||||||
|
|
||||||
function handleFavClick(coords: coords) {
|
function handleFavClick(coords: coords) {
|
||||||
center.value = [coords.lat, coords.lng];
|
center.value = [coords.lat, coords.lng];
|
||||||
markerLatLng.value = [coords.lat, coords.lng];
|
markerLatLng.value = [coords.lat, coords.lng];
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleControlClick(cmdAttr: CtrlAttr) {
|
function handleControlClick(cmdAttr) {
|
||||||
if (cmdAttr.cnfrm) {
|
if (cmdAttr.cnfrm) {
|
||||||
$q.dialog({
|
$q.dialog({
|
||||||
component: ConfirmCommandDialog,
|
component: ConfirmCommandDialog,
|
||||||
@@ -38,25 +36,33 @@ function handleControlClick(cmdAttr: CtrlAttr) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.onOk(() => {
|
.onOk(() => {
|
||||||
if (cmdAttr.cmdClass === 'simulation_control') {
|
if (cmdAttr.cmdClass === 'sim_cntrl_class') {
|
||||||
|
let notType: string = 'positive';
|
||||||
|
let notMsg: string = '';
|
||||||
try {
|
try {
|
||||||
const ack = socketStore.simulationControl(cmdAttr.cmd, cmdAttr.delay);
|
const ack = socketStore.simulationControl(cmdAttr['cmd'], cmdAttr.delay);
|
||||||
$q.notify({ type: 'positive', message: ack });
|
if (ack.sts === 'error') {
|
||||||
|
notType = 'negative';
|
||||||
|
}
|
||||||
|
if (ack.msg) {
|
||||||
|
notMsg = ack.msg;
|
||||||
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
notType = 'negative';
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
console.error('Simulation Command ERROR: ', error.message);
|
console.error('Simulation Command ERROR: ', error.message);
|
||||||
const ack = `Simulation Command Error: ${error.message}`;
|
notMsg = `Simulation Command Error: ${error.message}`;
|
||||||
$q.notify({ type: 'negative', message: ack });
|
|
||||||
} else {
|
} else {
|
||||||
console.error('Simmulation Command Error: ', error);
|
console.error('Simulation Command Error: ', error);
|
||||||
const ack = 'Simulation Command Error: Unknow error';
|
notMsg = 'Simulation Command Error: Unknow error';
|
||||||
$q.notify({ type: 'negative', message: ack });
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
$q.notify({ type: notType, message: notMsg });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctrl.cmdClass === 'device_control') {
|
if (cmdAttr.cmdClass === 'dev_cntrl_class') {
|
||||||
socket.emit('device_control', { command: ctrl.cmd, delay: 0 }, (response) => {
|
socket.emit('device_control', { command: cmdAttr.cmd, delay: 0 }, (response) => {
|
||||||
console.log(response.status, response.command);
|
console.log(response.status, response.command);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -68,22 +74,57 @@ function handleControlClick(cmdAttr: CtrlAttr) {
|
|||||||
console.log('Dialog dismissed');
|
console.log('Dialog dismissed');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (ctrl.cmdClass === 'simulation_control') {
|
if (cmdAttr.cmdClass === 'sim_cntrl_class') {
|
||||||
|
let notType: string = 'positive';
|
||||||
|
let notMsg: string = '';
|
||||||
try {
|
try {
|
||||||
const response = socketStore.simulationControl(ctrl.cmd);
|
const ack = socketStore.simulationControl(cmdAttr.cmd, cmdAttr.delay);
|
||||||
$q.notify({ type: 'positive', message: response });
|
if (ack.sts === 'error') {
|
||||||
} catch (error: unknown) {
|
notType = 'negative';
|
||||||
if (error instanceof Error) {
|
|
||||||
console.error('Error: ' + error.message);
|
|
||||||
$q.notify({ type: 'negative', message: error.toString() });
|
|
||||||
} else {
|
|
||||||
console.error('Error setting location:', error);
|
|
||||||
$q.notify({ type: 'negative', message: error.toString() });
|
|
||||||
}
|
}
|
||||||
|
if (ack.msg) {
|
||||||
|
notMsg = ack.msg;
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
notType = 'negative';
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.error('Simulation Command ERROR: ', error.message);
|
||||||
|
notMsg = `Simulation Command Error: ${error.message}`;
|
||||||
|
} else {
|
||||||
|
console.error('Simulation Command Error: ', error);
|
||||||
|
notMsg = 'Simulation Command Error: Unknow error';
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$q.notify({ type: notType, message: notMsg });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ctrl.cmdClass === 'device_control') {
|
if (cmdAttr.cmdClass === 'icloud-monitor_cntrl_class') {
|
||||||
socket.emit('device_control', { command: ctrl.cmd, delay: 0 }, (response) => {
|
let notType: string = 'positive';
|
||||||
|
let notMsg: string = '';
|
||||||
|
try {
|
||||||
|
const ack = socketStore.icloudMonitorControl(cmdAttr.cmd);
|
||||||
|
if (ack.sts === 'error') {
|
||||||
|
notType = 'negative';
|
||||||
|
}
|
||||||
|
if (ack.msg) {
|
||||||
|
notMsg = ack.msg;
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
notType = 'negative';
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.error('Simulation Command ERROR: ', error.message);
|
||||||
|
notMsg = `Simulation Command Error: ${error.message}`;
|
||||||
|
} else {
|
||||||
|
console.error('Simulation Command Error: ', error);
|
||||||
|
notMsg = 'Simulation Command Error: Unknow error';
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$q.notify({ type: notType, message: notMsg });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdAttr.cmdClass === 'dev_cntrl_class') {
|
||||||
|
socket.emit('device_control', { command: cmdAttr.cmd, delay: 0 }, (response) => {
|
||||||
console.log(response.status, response.command);
|
console.log(response.status, response.command);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -92,53 +133,59 @@ function handleControlClick(cmdAttr: CtrlAttr) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-toolbar class="bg-primary text-white">
|
<q-toolbar :class="testMode ? 'bg-warning text-black' : 'bg-primary text-white'">
|
||||||
<q-btn @click="$emit('drawer')" flat round dense icon="menu" class="q-mr-sm" />
|
<q-btn @click="$emit('drawer'); leafletStore.toggleQLocDrawer()" flat round dense icon="menu" class="q-mr-sm" />
|
||||||
<q-separator dark inset />
|
<q-separator dark inset />
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-btn :icon-right="menuOpen ? 'arrow_drop_up' : 'arrow_drop_down'" stretch flat label="Favorites" v-if="route.name === 'Leaflet'">
|
<q-btn
|
||||||
|
:icon-right="menuOpen ? 'arrow_drop_up' : 'arrow_drop_down'"
|
||||||
|
stretch
|
||||||
|
flat
|
||||||
|
label="Favorites"
|
||||||
|
v-if="route.name === 'Leaflet'"
|
||||||
|
>
|
||||||
<q-menu @show="menuOpen = true" @hide="menuOpen = false" anchor="bottom end" self="top end">
|
<q-menu @show="menuOpen = true" @hide="menuOpen = false" anchor="bottom end" self="top end">
|
||||||
<q-list>
|
<q-list>
|
||||||
<template v-for="fav, index) in favorites" :key="index">
|
<template v-for="(favObj, favId) in favorites" :key="favId">
|
||||||
<q-item
|
<q-item
|
||||||
v-if="fav.coords"
|
v-if="favObj.coords"
|
||||||
clickable
|
clickable
|
||||||
v-ripple
|
v-ripple
|
||||||
v-close-popup
|
v-close-popup
|
||||||
@click="handleFavClick(fav.coords)"
|
@click="handleFavClick(favObj.coords)"
|
||||||
>
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="fav.icon" color="primary" text-color="white" />
|
<q-avatar :icon="favObj.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ fav.name }}</q-item-label>
|
<q-item-label>{{ favObj.name }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item v-else clickable v-ripple>
|
<q-item v-else clickable v-ripple>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="fav.icon" color="primary" text-color="white" />
|
<q-avatar :icon="favObj.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ fav.name }}</q-item-label>
|
<q-item-label>{{ favObj.name }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
<q-icon name="keyboard_arrow_right" />
|
<q-icon name="keyboard_arrow_right" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-menu anchor="top end" self="top start">
|
<q-menu anchor="bottom start" self="bottom end">
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item
|
<q-item
|
||||||
v-for="(f, indx) in fav.subitems"
|
v-for="(favSubObj, favSubId) in favObj.subitems"
|
||||||
:key="indx"
|
:key="favSubId"
|
||||||
clickable
|
clickable
|
||||||
v-ripple
|
v-ripple
|
||||||
v-close-popup
|
v-close-popup
|
||||||
@click="handleFavClick(f.coords)"
|
@click="handleFavClick(favSubObj.coords)"
|
||||||
>
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="f.icon" color="primary" text-color="white" />
|
<q-avatar :icon="favSubObj.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ f.name }}</q-item-label>
|
<q-item-label>{{ favSubObj.name }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
@@ -156,12 +203,13 @@ function handleControlClick(cmdAttr: CtrlAttr) {
|
|||||||
clickable
|
clickable
|
||||||
v-ripple
|
v-ripple
|
||||||
v-close-popup
|
v-close-popup
|
||||||
@click="handleControlClick(controls.sim_start)">
|
@click="handleControlClick(controls.simulation.start)"
|
||||||
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="controls.sim_start.icon" color="primary" text-color="white" />
|
<q-avatar :icon="controls.simulation.start.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label> {{ controls.sim_start.name }} </q-item-label>
|
<q-item-label> {{ controls.simulation.start.name }} </q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item
|
<q-item
|
||||||
@@ -169,13 +217,13 @@ function handleControlClick(cmdAttr: CtrlAttr) {
|
|||||||
clickable
|
clickable
|
||||||
v-ripple
|
v-ripple
|
||||||
v-close-popup
|
v-close-popup
|
||||||
@click="handleControlClick(controls.sim_pause)"
|
@click="handleControlClick(controls.simulation.pause)"
|
||||||
>
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="controls.sim_pause.icon" color="primary" text-color="white" />
|
<q-avatar :icon="controls.simulation.pause.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label> {{ controls.sim_pause.name }} </q-item-label>
|
<q-item-label> {{ controls.simulation.pause.name }} </q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item
|
<q-item
|
||||||
@@ -183,27 +231,27 @@ function handleControlClick(cmdAttr: CtrlAttr) {
|
|||||||
clickable
|
clickable
|
||||||
v-ripple
|
v-ripple
|
||||||
v-close-popup
|
v-close-popup
|
||||||
@click="handleControlClick(controls.sim_resume)"
|
@click="handleControlClick(controls.simulation.resume)"
|
||||||
>
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="controls.sim_resume.icon" color="primary" text-color="white" />
|
<q-avatar :icon="controls.simulation.resume.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label> {{ controls.sim_resume.name }} </q-item-label>
|
<q-item-label> {{ controls.simulation.resume.name }} </q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item
|
<q-item
|
||||||
v-if="simulationQueueLength > 0"
|
v-if="simulationQueueLength && simulationQueueLength > 0"
|
||||||
clickable
|
clickable
|
||||||
v-ripple
|
v-ripple
|
||||||
v-close-popup
|
v-close-popup
|
||||||
@click="handleControlClick(controls.sim_clear)"
|
@click="handleControlClick(controls.simulation.clear)"
|
||||||
>
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="controls.sim_clear.icon" color="primary" text-color="white" />
|
<q-avatar :icon="controls.simulation.clear.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label> {{ controls.sim_clear.name }} </q-item-label>
|
<q-item-label> {{ controls.simulation.clear.name }} </q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item
|
<q-item
|
||||||
@@ -211,31 +259,75 @@ function handleControlClick(cmdAttr: CtrlAttr) {
|
|||||||
clickable
|
clickable
|
||||||
v-ripple
|
v-ripple
|
||||||
v-close-popup
|
v-close-popup
|
||||||
@click="handleControlClick(controls.sim_end)"
|
@click="handleControlClick(controls.simulation.end)"
|
||||||
>
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="controls.sim_end.icon" color="primary" text-color="white" />
|
<q-avatar :icon="controls.simulation.end.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label> {{ controls.sim_end.name }} </q-item-label>
|
<q-item-label> {{ controls.simulation.end.name }} </q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-separator spaced />
|
||||||
|
<q-item-label header>iCloud Monitor Controls</q-item-label>
|
||||||
|
<q-item
|
||||||
|
v-if="!icloudMonitor"
|
||||||
|
clickable
|
||||||
|
v-ripple
|
||||||
|
v-close-popup
|
||||||
|
@click="handleControlClick(controls.icloudmonitor.start)"
|
||||||
|
>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-avatar
|
||||||
|
v-if="icloudMonitor"
|
||||||
|
:icon="controls.icloudmonitor.start.icon"
|
||||||
|
color="primary"
|
||||||
|
text-color="white"
|
||||||
|
/>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label> {{ controls.icloudmonitor.start.name }} </q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-ripple
|
||||||
|
v-close-popup
|
||||||
|
@click="handleControlClick(controls.icloudmonitor.stop)"
|
||||||
|
>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-avatar :icon="controls.icloudmonitor.stop.icon" color="primary" text-color="white" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label> {{ controls.icloudmonitor.stop.name }} </q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-separator spaced />
|
<q-separator spaced />
|
||||||
<q-item-label header>Device Controls</q-item-label>
|
<q-item-label header>Device Controls</q-item-label>
|
||||||
<q-item clickable v-ripple v-close-popup @click="handleControlClick(controls.dev_reboot)">
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-ripple
|
||||||
|
v-close-popup
|
||||||
|
@click="handleControlClick(controls.device.reboot)"
|
||||||
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="controls.dev_reboot.icon" color="primary" text-color="white" />
|
<q-avatar :icon="controls.device.reboot.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label> {{ controls.dev_reboot.name }} </q-item-label>
|
<q-item-label> {{ controls.device.reboot.name }} </q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item clickable v-ripple v-close-popup @click="handleControlClick(controls.dev_shutdown)">
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-ripple
|
||||||
|
v-close-popup
|
||||||
|
@click="handleControlClick(controls.device.shutdown)"
|
||||||
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="controls.dev_shutdown.icon" color="primary" text-color="white" />
|
<q-avatar :icon="controls.device.shutdown.icon" color="primary" text-color="white" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label> {{ controls.dev_shutdown.name }} </q-item-label>
|
<q-item-label> {{ controls.device.shutdown.name }} </q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
|
|||||||
@@ -9,7 +9,14 @@
|
|||||||
<span class="q-ml-sm">
|
<span class="q-ml-sm">
|
||||||
Are you sure you want to set location to {{ latitude }}, {{ longitude }} ?
|
Are you sure you want to set location to {{ latitude }}, {{ longitude }} ?
|
||||||
</span>
|
</span>
|
||||||
<q-input dense v-model="delay" autofocus @keyup.enter="onOkClick" label="Delay (seconds)" type="number" />
|
<q-input
|
||||||
|
dense
|
||||||
|
v-model="delay"
|
||||||
|
autofocus
|
||||||
|
@keyup.enter="onOkClick"
|
||||||
|
label="Delay (seconds)"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-actions align="right">
|
<q-card-actions align="right">
|
||||||
<q-btn flat label="OK" color="primary" @click="onOkClick" />
|
<q-btn flat label="OK" color="primary" @click="onOkClick" />
|
||||||
@@ -37,6 +44,6 @@ defineEmits([...useDialogPluginComponent.emits]);
|
|||||||
const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
|
const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
|
||||||
|
|
||||||
function onOkClick() {
|
function onOkClick() {
|
||||||
onDialogOK();
|
onDialogOK(delay.value);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const {
|
|||||||
deviceConnected,
|
deviceConnected,
|
||||||
tunnelConnected,
|
tunnelConnected,
|
||||||
simulationRunning,
|
simulationRunning,
|
||||||
|
icloudMonitor,
|
||||||
currentLocation,
|
currentLocation,
|
||||||
nextLocation,
|
nextLocation,
|
||||||
} = storeToRefs(socketioStore);
|
} = storeToRefs(socketioStore);
|
||||||
@@ -33,23 +34,54 @@ function statusDevColor(state: string | boolean): string {
|
|||||||
<q-toolbar class="bg-primary text-white">
|
<q-toolbar class="bg-primary text-white">
|
||||||
<div class="flex col q-gutter-md align-center justify-start content-center">
|
<div class="flex col q-gutter-md align-center justify-start content-center">
|
||||||
<q-space />
|
<q-space />
|
||||||
<span>Status:</span>
|
<div style="width: 80vw" class="flex justify-end">
|
||||||
<span>
|
<q-btn
|
||||||
<q-badge :color="statusDevColor(sockConnected)" rounded class="q-mr-sm" />
|
size="sm"
|
||||||
<q-btn label="WebSocket" @click="socketioStore.toggleSock()" />
|
rounded
|
||||||
</span>
|
push
|
||||||
<span>
|
icon="settings"
|
||||||
<q-badge :color="statusDevColor(deviceConnected)" rounded class="q-mr-sm" />
|
class="q-mr-sm"
|
||||||
Device Connection
|
@click="socketioStore.toggleSock()"
|
||||||
</span>
|
>
|
||||||
<span>
|
<q-badge :color="statusDevColor(sockConnected)" rounded floating class="q-mr-sm" />
|
||||||
<q-badge :color="statusDevColor(tunnelConnected)" rounded class="q-mr-sm" />
|
</q-btn>
|
||||||
tunneld
|
<q-btn size="sm" rounded icon="phone_iphone" class="q-mr-sm">
|
||||||
</span>
|
<q-badge
|
||||||
<span>
|
:color="statusDevColor(deviceConnected)"
|
||||||
<q-badge :color="statusDevColor(simulationRunning)" rounded class="q-mr-sm" />
|
@click="socketioStore.requestUpdate()"
|
||||||
Location Simulation
|
rounded
|
||||||
</span>
|
floating
|
||||||
|
class="q-mr-sm"
|
||||||
|
/>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn
|
||||||
|
size="sm"
|
||||||
|
@click="socketioStore.toggleTunneld()"
|
||||||
|
rounded
|
||||||
|
icon="subway"
|
||||||
|
class="q-mr-sm"
|
||||||
|
>
|
||||||
|
<q-badge :color="statusDevColor(tunnelConnected)" rounded floating class="q-mr-sm" />
|
||||||
|
</q-btn>
|
||||||
|
<q-btn
|
||||||
|
size="sm"
|
||||||
|
@click="socketioStore.requestUpdate()"
|
||||||
|
rounded
|
||||||
|
icon="location_on"
|
||||||
|
class="q-mr-sm"
|
||||||
|
>
|
||||||
|
<q-badge :color="statusDevColor(simulationRunning)" rounded floating class="q-mr-sm" />
|
||||||
|
</q-btn>
|
||||||
|
<q-btn
|
||||||
|
size="sm"
|
||||||
|
@click="socketioStore.requestUpdate()"
|
||||||
|
rounded
|
||||||
|
icon="cloud"
|
||||||
|
class="q-mr-sm"
|
||||||
|
>
|
||||||
|
<q-badge :color="statusDevColor(icloudMonitor)" rounded floating class="q-mr-sm" />
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
41
src/components/iCloudCodeDialog.vue
Normal file
41
src/components/iCloudCodeDialog.vue
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<q-dialog ref="dlgRef" persistent>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section class="row items-center">
|
||||||
|
<q-avatar icon="password_2" color="primary" text-color="white" />
|
||||||
|
<span class="q-ml-sm"> iCloud Account requires Two-factor authentication.</span>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
v-model="code"
|
||||||
|
mask="######"
|
||||||
|
autofocus
|
||||||
|
@keyup.enter="onOkClick"
|
||||||
|
label="Delay (seconds)"
|
||||||
|
type="number"
|
||||||
|
:rules="[(val) => val.length === 6 || 'Must be 6 digits']"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn flat label="OK" color="primary" @click="onOkClick" />
|
||||||
|
<q-btn flat label="Cancel" color="primary" @click="onDialogCancel" />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const code = ref('');
|
||||||
|
|
||||||
|
defineEmits([...useDialogPluginComponent.emits]);
|
||||||
|
|
||||||
|
const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
|
||||||
|
|
||||||
|
function onOkClick() {
|
||||||
|
onDialogOK(code.value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
|
|
||||||
export type SimulationCommands = "start" | "pause" | "resume" | "clear" | "end" | "add";
|
|
||||||
|
|
||||||
export type DeviceCommands= "start_tunnel" | "stop_tunnel" | "shutdown";
|
|
||||||
|
|
||||||
export interface CtrlAttrs {
|
export interface CtrlAttrs {
|
||||||
[key: string]: CtrlAttr;
|
[key: string]: CtrlAttr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type SimulationCommands = 'start' | 'pause' | 'resume' | 'clear' | 'end' | 'add';
|
||||||
|
|
||||||
|
export type DeviceCommands = 'start_tunnel' | 'stop_tunnel' | 'shutdown' | 'reboot';
|
||||||
|
|
||||||
|
export type TunnelCommands = 'start' | 'start-watcher' | 'end-watcher' | 'shutdown' | 'restart' | 'clear' | 'cancel' ;
|
||||||
|
|
||||||
export interface CtrlAttr {
|
export interface CtrlAttr {
|
||||||
name: string;
|
name: string;
|
||||||
cmd: string;
|
cmd: string;
|
||||||
@@ -16,6 +18,15 @@ export interface CtrlAttr {
|
|||||||
delay: number;
|
delay: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DevCtrlAttr {
|
||||||
|
name: string;
|
||||||
|
cmd: DeviceCommands;
|
||||||
|
cmdClass: 'device_control';
|
||||||
|
icon: string;
|
||||||
|
cnfrm: boolean;
|
||||||
|
delay: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface LocationQueue {
|
export interface LocationQueue {
|
||||||
[key: string]: LocationMark
|
[key: string]: LocationMark
|
||||||
}
|
}
|
||||||
@@ -24,9 +35,155 @@ interface LocationMark {
|
|||||||
loc_id: string;
|
loc_id: string;
|
||||||
latitude: number | undefined | null;
|
latitude: number | undefined | null;
|
||||||
longitude: number | undefined | null;
|
longitude: number | undefined | null;
|
||||||
|
address?: string | undefined | null;
|
||||||
delay?: number | undefined | null;
|
delay?: number | undefined | null;
|
||||||
start_time: string | undefined | null;
|
start?: string | undefined | null;
|
||||||
end_time?: string | undefined | null ;
|
end?: string | undefined | null ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SERVER TO CLIENT
|
||||||
|
|
||||||
|
export interface ServerToClientEvents {
|
||||||
|
noArg: () => void;
|
||||||
|
withAck: (a: string, callback: (b: number) => void) => void;
|
||||||
|
simulation_status: (c: SimulationStatus) => void;
|
||||||
|
status: (d: StatusUpdate) => void;
|
||||||
|
device_status: (d: DeviceStatus) => void;
|
||||||
|
error: (data: ErrorFull) => void;
|
||||||
|
message: (e: string) => void;
|
||||||
|
icloud_2fa_request: (callback: (e: number) => void) => void;
|
||||||
|
fmf_update: (d: FindMyUpdate) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SimulationStatus {
|
||||||
|
status: boolean;
|
||||||
|
data: {
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
start: string;
|
||||||
|
end?: string;
|
||||||
|
next_move?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StatusUpdate {
|
||||||
|
connected_clients: { [key: string]: string };
|
||||||
|
current_location: {
|
||||||
|
loc_id: string;
|
||||||
|
latitude: number | undefined | null;
|
||||||
|
longitude: number | undefined | null;
|
||||||
|
start?: string | undefined | null;
|
||||||
|
};
|
||||||
|
device_name: string | undefined | null;
|
||||||
|
fmf_location: FindMyUpdate | undefined | null;
|
||||||
|
icloud: {
|
||||||
|
consumer_queue: number | undefined | null;
|
||||||
|
consumer_task: string | undefined | null;
|
||||||
|
monitor_enabled: boolean;
|
||||||
|
monitor_task: string | undefined | null;
|
||||||
|
monitor_running: boolean;
|
||||||
|
};
|
||||||
|
next_move?: number | undefined | null;
|
||||||
|
set_location_enabled: boolean;
|
||||||
|
simulation_queue: {
|
||||||
|
active: boolean;
|
||||||
|
data: {
|
||||||
|
[key: string]: LocationMark;
|
||||||
|
};
|
||||||
|
order: string[];
|
||||||
|
state: string | undefined | null;
|
||||||
|
worker_task: string | undefined | null;
|
||||||
|
};
|
||||||
|
test_mode: boolean;
|
||||||
|
tunnel: string | undefined | null;
|
||||||
|
tunnel_watcher_running: boolean;
|
||||||
|
device_count?: number | undefined | null;
|
||||||
|
udid?: string | null;
|
||||||
|
product_version?: string | null | undefined;
|
||||||
|
phone_number?: string | null | undefined;
|
||||||
|
developer_mode_enabled?: boolean | undefined | null;
|
||||||
|
ddi_mounted?: boolean;
|
||||||
|
rsd_address?: string | null | undefined;
|
||||||
|
rsd_port?: number | undefined | null;
|
||||||
|
lockdown_trusted_port?: number | undefined | null;
|
||||||
|
lockdown_untrusted_port?: number | undefined | null;
|
||||||
|
lockdown_trusted_reachable?: boolean | undefined | null;
|
||||||
|
lockdown_untrusted_reachable?: boolean | undefined | null;
|
||||||
|
dtservicehub_reachable?: boolean | undefined | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeviceStatus {
|
||||||
|
device_connected: boolean;
|
||||||
|
device_count: number;
|
||||||
|
udid?: string | null;
|
||||||
|
device_name?: string | null;
|
||||||
|
product_version?: string | null;
|
||||||
|
phone_number?: string | null;
|
||||||
|
developer_mode_enabled?: boolean;
|
||||||
|
ddi_mounted?: boolean;
|
||||||
|
rsd_address?: string | null;
|
||||||
|
rsd_port?: number;
|
||||||
|
lockdown_trusted_port?: number;
|
||||||
|
lockdown_untrusted_port?: number;
|
||||||
|
lockdown_trusted_reachable?: boolean;
|
||||||
|
lockdown_untrusted_reachable?: boolean;
|
||||||
|
dtservicehub_reachable?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ErrorFull {
|
||||||
|
type: string;
|
||||||
|
error: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FindMyUpdate {
|
||||||
|
altitude: number;
|
||||||
|
batteryLevel: number;
|
||||||
|
deviceDisplayName: string;
|
||||||
|
deviceStatus: number;
|
||||||
|
horizontalAccuracy: number;
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
name: string;
|
||||||
|
timeStamp: number;
|
||||||
|
verticalAccuracy: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// END SERVER TO CLIENT
|
||||||
|
|
||||||
|
// CLIENT TO SERVER
|
||||||
|
|
||||||
|
export interface ClientToServerEvents {
|
||||||
|
message: (e: string, callback: (b: boolean, r: string) => void) => void;
|
||||||
|
request_update: (callback: (response: StatusUpdate) => void) => void;
|
||||||
|
simulation_control: (
|
||||||
|
args: {
|
||||||
|
command: SimulationCommands;
|
||||||
|
latitude?: number | null | undefined;
|
||||||
|
longitude?: number | null | undefined;
|
||||||
|
delay?: number | undefined;
|
||||||
|
},
|
||||||
|
callback: (response: SimulationControlResponse) => void,
|
||||||
|
) => void;
|
||||||
|
device_control: (
|
||||||
|
args: {
|
||||||
|
command: DeviceCommands;
|
||||||
|
delay?: number;
|
||||||
|
},
|
||||||
|
callback?: (response: DeviceControlResponse) => void,
|
||||||
|
) => void;
|
||||||
|
tunnel_control: (
|
||||||
|
args: {
|
||||||
|
command: TunnelCommands;
|
||||||
|
delay?: number;
|
||||||
|
},
|
||||||
|
callback?: (response: DeviceControlResponse) => void,
|
||||||
|
) => void;
|
||||||
|
icloud_monitor_control: (
|
||||||
|
args: {
|
||||||
|
command: string;
|
||||||
|
},
|
||||||
|
callback?: (response: iCloudMonitorResponse) => void,
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SimulationControlResponse {
|
export interface SimulationControlResponse {
|
||||||
@@ -47,119 +204,20 @@ interface DeviceControlResponse {
|
|||||||
delay?: number;
|
delay?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StatusUpdate {
|
export interface iCloudMonitorResponse {
|
||||||
simulation_active: boolean;
|
status: string;
|
||||||
set_location_enabled: boolean;
|
command: string;
|
||||||
queue: number,
|
icloud_monitor_enabled?: boolean | undefined | null;
|
||||||
latitude: number | undefined | null;
|
icloud_monitor_running?: boolean | undefined | null;
|
||||||
longitude: number | undefined | null;
|
message?: string | undefined | null;
|
||||||
next_move?: number | undefined | null;
|
|
||||||
queue_list: LocationQueue[]
|
|
||||||
queue_state: string | undefined | null;
|
|
||||||
queue_status: boolean;
|
|
||||||
simulation_task: string | undefined | null;
|
|
||||||
test_mode: boolean
|
|
||||||
tunnel: string | undefined | null;
|
|
||||||
device_count?: number | undefined | null;
|
|
||||||
udid?: string | null;
|
|
||||||
device_name?: string | null | undefined;
|
|
||||||
product_version?: string | null | undefined;
|
|
||||||
phone_number?: string | null | undefined;
|
|
||||||
developer_mode_enabled?: boolean | undefined | null;
|
|
||||||
ddi_mounted?: boolean ;
|
|
||||||
rsd_address?: string | null | undefined;
|
|
||||||
rsd_port?: number | undefined | null;
|
|
||||||
lockdown_trusted_port?: number | undefined | null;
|
|
||||||
lockdown_untrusted_port?: number | undefined | null;
|
|
||||||
lockdown_trusted_reachable?: boolean | undefined | null;
|
|
||||||
lockdown_untrusted_reachable?: boolean | undefined | null;
|
|
||||||
dtservicehub_reachable?: boolean | undefined | null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerToClientEvents {
|
// END CLIENT TO SERVER
|
||||||
noArg: () => void;
|
|
||||||
withAck: (a: string, callback: (b: number) => void) => void;
|
|
||||||
simulationStatus: (c: SimulationStatus) => void;
|
|
||||||
status: (d: StatusUpdate) => void;
|
|
||||||
device_status: (d: DeviceStatus) => void;
|
|
||||||
error: (data: ErrorFull) => void;
|
|
||||||
message: (e: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientToServerEvents {
|
|
||||||
message: (e: string, callback: (b: boolean, r: string) => void) => void;
|
|
||||||
simulation_control: (
|
|
||||||
args: {
|
|
||||||
command: SimulationCommands,
|
|
||||||
latitude?: number | null | undefined,
|
|
||||||
longitude?: number | null | undefined,
|
|
||||||
delay?: number | undefined
|
|
||||||
},
|
|
||||||
callback: (response: SimulationControlResponse) => void
|
|
||||||
) => void;
|
|
||||||
device_control: (
|
|
||||||
args: {
|
|
||||||
command: DeviceCommands,
|
|
||||||
delay?: number
|
|
||||||
},
|
|
||||||
callback?: (response: DeviceControlResponse) => void
|
|
||||||
) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SimulationStatus {
|
|
||||||
status: boolean;
|
|
||||||
data: {
|
|
||||||
latitude: number;
|
|
||||||
longitude: number;
|
|
||||||
start: string;
|
|
||||||
end?: string;
|
|
||||||
next_move?: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Meta {
|
export interface Meta {
|
||||||
totalCount: number;
|
totalCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface DeviceStatus {
|
|
||||||
device_connected: boolean;
|
|
||||||
device_count: number;
|
|
||||||
udid?: string | null;
|
|
||||||
device_name?: string | null;
|
|
||||||
product_version?: string | null;
|
|
||||||
phone_number?: string | null;
|
|
||||||
developer_mode_enabled?: boolean;
|
|
||||||
ddi_mounted?: boolean;
|
|
||||||
rsd_address?: string | null;
|
|
||||||
rsd_port?: number;
|
|
||||||
lockdown_trusted_port?: number;
|
|
||||||
lockdown_untrusted_port?: number;
|
|
||||||
lockdown_trusted_reachable?: boolean;
|
|
||||||
lockdown_untrusted_reachable?: boolean;
|
|
||||||
dtservicehub_reachable?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Control = DeviceControl | SimulationControl;
|
|
||||||
|
|
||||||
export interface DeviceControl {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
cmd: DeviceCommands
|
|
||||||
cmdClass: "device_control"
|
|
||||||
icon: string;
|
|
||||||
confirm: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SimulationControl {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
cmd: SimulationCommands;
|
|
||||||
cmdClass: 'simulation_control';
|
|
||||||
icon: string;
|
|
||||||
confirm: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface coords {
|
export interface coords {
|
||||||
lat: number;
|
lat: number;
|
||||||
lng: number;
|
lng: number;
|
||||||
@@ -183,9 +241,11 @@ export interface SearchControlProps {
|
|||||||
|
|
||||||
export interface CurrentLocation {
|
export interface CurrentLocation {
|
||||||
loc_id: string;
|
loc_id: string;
|
||||||
latitude: number;
|
latitude: number| null | undefined;
|
||||||
longitude: number;
|
longitude: number| null | undefined;
|
||||||
next_move?: number | null
|
// start_time?: string | null | undefined;
|
||||||
|
// end_time?: string | null | undefined
|
||||||
|
next_move?: number | null | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NextLocation {
|
export interface NextLocation {
|
||||||
@@ -195,7 +255,4 @@ export interface NextLocation {
|
|||||||
time_at_location?: number | null;
|
time_at_location?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ErrorFull {
|
|
||||||
type: string;
|
|
||||||
error: string;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,62 +1,82 @@
|
|||||||
import type { CtrlAttrs } from 'components/models';
|
import type { CtrlAttrs } from 'components/models';
|
||||||
|
|
||||||
export const controls: CtrlAttrs = {
|
export const controls = {
|
||||||
sim_start: {
|
simulation: {
|
||||||
name: 'Start Location Sim',
|
start: {
|
||||||
cmd: 'start',
|
name: 'Start Location Sim',
|
||||||
cmdClass: 'simulation_control',
|
cmd: 'start',
|
||||||
icon: 'play_arrow',
|
cmdClass: 'sim_cntrl_class',
|
||||||
cnfrm: false,
|
icon: 'play_arrow',
|
||||||
delay: 0,
|
cnfrm: false,
|
||||||
|
delay: 0,
|
||||||
|
},
|
||||||
|
pause: {
|
||||||
|
name: 'Pause Location Sim',
|
||||||
|
cmd: 'pause',
|
||||||
|
cmdClass: 'sim_cntrl_class',
|
||||||
|
icon: 'pause',
|
||||||
|
cnfrm: false,
|
||||||
|
delay: 0,
|
||||||
|
},
|
||||||
|
resume: {
|
||||||
|
name: 'Resume Location Simulation',
|
||||||
|
cmd: 'resume',
|
||||||
|
cmdClass: 'sim_cntrl_class',
|
||||||
|
icon: 'play_arrow',
|
||||||
|
cnfrm: false,
|
||||||
|
delay: 0,
|
||||||
|
},
|
||||||
|
clear: {
|
||||||
|
name: 'Clear Location Queue',
|
||||||
|
cmd: 'clear',
|
||||||
|
cmdClass: 'sim_cntrl_class',
|
||||||
|
icon: 'directions_off',
|
||||||
|
cnfrm: false,
|
||||||
|
delay: 0,
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
name: 'End Location Sim',
|
||||||
|
cmd: 'end',
|
||||||
|
cmdClass: 'sim_cntrl_class',
|
||||||
|
icon: 'stop',
|
||||||
|
cnfrm: true,
|
||||||
|
delay: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
sim_pause: {
|
device: {
|
||||||
name: 'Pause Location Sim',
|
shutdown: {
|
||||||
cmd: 'pause',
|
name: 'Shutdown',
|
||||||
cmdClass: 'simulation_control',
|
cmd: 'shutdown',
|
||||||
icon: 'pause',
|
cmdClass: 'dev_cntrl_class',
|
||||||
cnfrm: false,
|
icon: 'power_settings_new',
|
||||||
delay: 0,
|
cnfrm: true,
|
||||||
},
|
delay: 5,
|
||||||
sim_resume: {
|
},
|
||||||
name: 'Resume Location Simulation',
|
reboot: {
|
||||||
cmd: 'resume',
|
name: 'Reboot',
|
||||||
cmdClass: 'simulation_control',
|
cmd: 'reboot',
|
||||||
icon: 'play_arrow',
|
cmdClass: 'dev_cntrl_class',
|
||||||
cnfrm: false,
|
icon: 'restart_alt',
|
||||||
delay: 0,
|
cnfrm: true,
|
||||||
},
|
delay: 5,
|
||||||
sim_clear: {
|
}
|
||||||
name: 'Clear Location Queue',
|
|
||||||
cmd: 'clear',
|
|
||||||
cmdClass: 'simulation_control',
|
|
||||||
icon: 'directions_off',
|
|
||||||
cnfrm: false,
|
|
||||||
delay: 0,
|
|
||||||
},
|
|
||||||
sim_end: {
|
|
||||||
name: 'End Location Sim',
|
|
||||||
cmd: 'end',
|
|
||||||
cmdClass: 'simulation_control',
|
|
||||||
icon: 'stop',
|
|
||||||
cnfrm: true,
|
|
||||||
delay: 0,
|
|
||||||
},
|
|
||||||
dev_shutdown: {
|
|
||||||
name: 'Shutdown',
|
|
||||||
cmd: 'shutdown',
|
|
||||||
cmdClass: 'device_control',
|
|
||||||
icon: 'power_settings_new',
|
|
||||||
cnfrm: true,
|
|
||||||
delay: 5,
|
|
||||||
},
|
|
||||||
dev_reboot: {
|
|
||||||
name: 'Reboot',
|
|
||||||
cmd: 'reboot',
|
|
||||||
cmdClass: 'device_control',
|
|
||||||
icon: 'restart_alt',
|
|
||||||
cnfrm: true,
|
|
||||||
delay: 5,
|
|
||||||
},
|
},
|
||||||
|
icloudmonitor: {
|
||||||
|
start: {
|
||||||
|
name: 'Start iCloud Monitor',
|
||||||
|
cmd: 'start',
|
||||||
|
cmdClass: 'icloud-monitor_cntrl_class',
|
||||||
|
icon: 'play_arrow',
|
||||||
|
cnfrm: false,
|
||||||
|
delay: 0,
|
||||||
|
},
|
||||||
|
stop: {
|
||||||
|
name: 'Stop iCloud Monitor',
|
||||||
|
cmd: 'stop',
|
||||||
|
cmdClass: 'icloud-monitor_cntrl_class',
|
||||||
|
icon: 'stop',
|
||||||
|
cnfrm: false,
|
||||||
|
delay: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export const favorites = [
|
export const favorites = {
|
||||||
{
|
home: {
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
icon: 'home',
|
icon: 'home',
|
||||||
coords: {
|
coords: {
|
||||||
@@ -7,11 +7,11 @@ export const favorites = [
|
|||||||
lng: -73.891069806448,
|
lng: -73.891069806448,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
work_places: {
|
||||||
name: "Work Places",
|
name: 'Work Places',
|
||||||
icon: "work",
|
icon: 'work',
|
||||||
subitems: [
|
subitems: {
|
||||||
{
|
jeong: {
|
||||||
name: 'Jeong',
|
name: 'Jeong',
|
||||||
icon: 'language_korean_latin',
|
icon: 'language_korean_latin',
|
||||||
coords: {
|
coords: {
|
||||||
@@ -20,17 +20,17 @@ export const favorites = [
|
|||||||
},
|
},
|
||||||
address: '35-02 150th Pl, Flushing, NY 11354',
|
address: '35-02 150th Pl, Flushing, NY 11354',
|
||||||
},
|
},
|
||||||
{
|
santos: {
|
||||||
name: 'Santos',
|
name: 'Santos',
|
||||||
icon: 'rice_bowl',
|
icon: 'rice_bowl',
|
||||||
coords: {
|
coords: {
|
||||||
lat: 40.74504671877868,
|
lat: 40.74504671877868,
|
||||||
lng: -73.8880099638491,
|
lng: -73.8880099638491,
|
||||||
},
|
},
|
||||||
address: '77-08 Broadway, Elmhurst, NY 11373'
|
address: '77-08 Broadway, Elmhurst, NY 11373',
|
||||||
},
|
},
|
||||||
{
|
natalya_qns: {
|
||||||
name: 'Natalyaa (Qns)',
|
name: 'Natalya (Qns)',
|
||||||
icon: 'currency_ruble',
|
icon: 'currency_ruble',
|
||||||
coords: {
|
coords: {
|
||||||
lat: 40.69644966409178,
|
lat: 40.69644966409178,
|
||||||
@@ -38,8 +38,8 @@ export const favorites = [
|
|||||||
},
|
},
|
||||||
address: '110-14 Jamaica Ave, Richmond Hill, NY 11418',
|
address: '110-14 Jamaica Ave, Richmond Hill, NY 11418',
|
||||||
},
|
},
|
||||||
{
|
natalya_bx: {
|
||||||
name: 'Natalyaa (Bronx)',
|
name: 'Natalya (Bronx)',
|
||||||
icon: 'currency_ruble',
|
icon: 'currency_ruble',
|
||||||
coords: {
|
coords: {
|
||||||
lat: 40.85384419116598,
|
lat: 40.85384419116598,
|
||||||
@@ -47,7 +47,7 @@ export const favorites = [
|
|||||||
},
|
},
|
||||||
address: '2109 Matthews Ave, Bronx, NY 10462',
|
address: '2109 Matthews Ave, Bronx, NY 10462',
|
||||||
},
|
},
|
||||||
{
|
office: {
|
||||||
name: 'Linwood Plaza',
|
name: 'Linwood Plaza',
|
||||||
icon: 'dermatology',
|
icon: 'dermatology',
|
||||||
coords: {
|
coords: {
|
||||||
@@ -56,9 +56,9 @@ export const favorites = [
|
|||||||
},
|
},
|
||||||
address: '158 Linwood Plaza, Fort Lee, NJ 07024',
|
address: '158 Linwood Plaza, Fort Lee, NJ 07024',
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
},
|
},
|
||||||
{
|
strg: {
|
||||||
name: 'Man Mini Storage',
|
name: 'Man Mini Storage',
|
||||||
icon: 'box',
|
icon: 'box',
|
||||||
coords: {
|
coords: {
|
||||||
@@ -67,8 +67,8 @@ export const favorites = [
|
|||||||
},
|
},
|
||||||
address: '31-08 Northern Blvd, Long Island City, NY 11101',
|
address: '31-08 Northern Blvd, Long Island City, NY 11101',
|
||||||
},
|
},
|
||||||
{
|
acme: {
|
||||||
name: 'Acmd',
|
name: 'Acme',
|
||||||
icon: 'grocery',
|
icon: 'grocery',
|
||||||
coords: {
|
coords: {
|
||||||
lat: 40.90930366920829,
|
lat: 40.90930366920829,
|
||||||
@@ -76,4 +76,4 @@ export const favorites = [
|
|||||||
},
|
},
|
||||||
address: '31-08 Northern Blvd, Long Island City, NY 11101',
|
address: '31-08 Northern Blvd, Long Island City, NY 11101',
|
||||||
},
|
},
|
||||||
];
|
};
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { Utilities } from "@vue-leaflet/vue-leaflet";
|
import { Utilities } from '@vue-leaflet/vue-leaflet';
|
||||||
import type * as L from "leaflet";
|
import type L from 'leaflet';
|
||||||
import type { IRouter, IGeocoder, LineOptions } from "leaflet-routing-machine";
|
import type { IRouter, IGeocoder, LineOptions } from 'leaflet-routing-machine';
|
||||||
|
|
||||||
// Props typing
|
// ---- Props typing ----
|
||||||
export interface RoutingControlProps {
|
export interface RoutingControlProps {
|
||||||
waypoints: L.LatLng[];
|
waypoints: L.Routing.Waypoint[];
|
||||||
router?: IRouter;
|
router?: IRouter;
|
||||||
plan?: any; // L.Routing.Plan (can refine if you typed it)
|
plan?: L.Routing.Plan;
|
||||||
fitSelectedRoutes?: string | boolean;
|
fitSelectedRoutes?: string | boolean;
|
||||||
lineOptions?: LineOptions;
|
lineOptions?: LineOptions;
|
||||||
routeLine?: (...args: any[]) => any;
|
routeLine?: (route: any) => L.Layer;
|
||||||
autoRoute?: boolean;
|
autoRoute?: boolean;
|
||||||
routeWhileDragging?: boolean;
|
routeWhileDragging?: boolean;
|
||||||
routeDragInterval?: number;
|
routeDragInterval?: number;
|
||||||
@@ -19,30 +19,30 @@ export interface RoutingControlProps {
|
|||||||
altLineOptions?: LineOptions;
|
altLineOptions?: LineOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vue-style prop definitions (still needed for runtime)
|
// ---- Vue-compatible prop definition ----
|
||||||
export const routingControlProps = {
|
export const routingControlProps = {
|
||||||
waypoints: {
|
waypoints: {
|
||||||
type: Array as () => L.LatLng[],
|
type: Array as () => L.Routing.Waypoint[],
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
router: {
|
router: {
|
||||||
type: Object as () => IRouter,
|
type: Object as () => IRouter | undefined,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
plan: {
|
plan: {
|
||||||
type: Object as () => any,
|
type: Object as () => L.Routing.Plan | undefined,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
fitSelectedRoutes: {
|
fitSelectedRoutes: {
|
||||||
type: [String, Boolean] as () => string | boolean,
|
type: [String, Boolean] as unknown as () => string | boolean,
|
||||||
default: "smart",
|
default: 'smart',
|
||||||
},
|
},
|
||||||
lineOptions: {
|
lineOptions: {
|
||||||
type: Object as () => LineOptions,
|
type: Object as () => LineOptions | undefined,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
routeLine: {
|
routeLine: {
|
||||||
type: Function as () => (...args: any[]) => any,
|
type: Function as unknown as () => ((route: any) => L.Layer) | undefined,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
autoRoute: {
|
autoRoute: {
|
||||||
@@ -59,7 +59,7 @@ export const routingControlProps = {
|
|||||||
},
|
},
|
||||||
waypointMode: {
|
waypointMode: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "connect",
|
default: 'connect',
|
||||||
},
|
},
|
||||||
useZoomParameter: {
|
useZoomParameter: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -70,17 +70,17 @@ export const routingControlProps = {
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
altLineOptions: {
|
altLineOptions: {
|
||||||
type: Object as () => LineOptions,
|
type: Object as () => LineOptions | undefined,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup function
|
// ---- Setup function ----
|
||||||
export const setupRoutingControl = (props: RoutingControlProps) => {
|
export const setupRoutingControl = (props: RoutingControlProps) => {
|
||||||
const options = Utilities.propsToLeafletOptions(
|
const options = Utilities.propsToLeafletOptions(
|
||||||
props,
|
props,
|
||||||
routingControlProps
|
routingControlProps,
|
||||||
);
|
) as L.Routing.RoutingControlOptions;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
options,
|
options,
|
||||||
|
|||||||
@@ -1,19 +1,36 @@
|
|||||||
import { defineStore, acceptHMRUpdate } from 'pinia';
|
import { defineStore, acceptHMRUpdate } from 'pinia';
|
||||||
|
import { favorites } from 'constants/favorites'
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
zoom: number
|
zoom: number
|
||||||
center: [number, number]
|
center: [number, number] | [null, null] | null
|
||||||
markerLatLng: [number, number]
|
markerLatLng: [number, number] | [null, null] | null
|
||||||
|
qLocDrawer: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useLeafletStore = defineStore('leaflet', {
|
export const useLeafletStore = defineStore('leaflet', {
|
||||||
state: (): State => {
|
state: (): State => {
|
||||||
return {
|
return {
|
||||||
zoom: 10,
|
zoom: 10,
|
||||||
center: [40.71278, -74.00594],
|
center: [favorites.home.coords.lat, favorites.home.coords.lng],
|
||||||
markerLatLng: [40.71278, -74.00594],
|
markerLatLng: null,
|
||||||
|
qLocDrawer: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
actions: {
|
||||||
|
setCenter(lat: number, lng: number) {
|
||||||
|
this.center = [lat, lng];
|
||||||
|
},
|
||||||
|
setZoom(zoom: number) {
|
||||||
|
this.zoom = zoom;
|
||||||
|
},
|
||||||
|
setMarkerLatLng(lat: number, lng: number) {
|
||||||
|
this.markerLatLng = [lat, lng];
|
||||||
|
},
|
||||||
|
toggleQLocDrawer() {
|
||||||
|
this.qLocDrawer = !this.qLocDrawer
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (import.meta.hot) {
|
if (import.meta.hot) {
|
||||||
|
|||||||
@@ -1,48 +1,61 @@
|
|||||||
import { defineStore, acceptHMRUpdate } from 'pinia';
|
import { defineStore, acceptHMRUpdate } from 'pinia';
|
||||||
import { socket } from 'boot/socketio';
|
import { socket } from 'boot/socketio';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
import iCloudCodeDialog from 'components/iCloudCodeDialog.vue';
|
||||||
import type {
|
import type {
|
||||||
CurrentLocation,
|
CurrentLocation,
|
||||||
NextLocation,
|
NextLocation,
|
||||||
ErrorFull,
|
ErrorFull,
|
||||||
SimulationControl,
|
|
||||||
SimulationCommands,
|
|
||||||
LocationQueue,
|
LocationQueue,
|
||||||
SimulationControlResponse,
|
SimulationControlResponse,
|
||||||
StatusUpdate
|
StatusUpdate,
|
||||||
|
FindMyUpdate,
|
||||||
|
iCloudMonitorResponse,
|
||||||
} from 'components/models';
|
} from 'components/models';
|
||||||
|
|
||||||
|
|
||||||
|
const $q = useQuasar();
|
||||||
|
const debugLog: boolean = true;
|
||||||
|
|
||||||
export const useSocketioStore = defineStore('socketio', {
|
export const useSocketioStore = defineStore('socketio', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
sockConnected: false as boolean,
|
sockConnected: false as boolean,
|
||||||
socketID: null as string | null | undefined,
|
socketID: null as string | null | undefined,
|
||||||
|
testMode: null as boolean | undefined | null,
|
||||||
deviceConnected: false as boolean,
|
deviceConnected: false as boolean,
|
||||||
tunnelConnected: false as boolean,
|
tunnelConnected: false as boolean,
|
||||||
simulationRunning: false as boolean | string,
|
simulationRunning: false as boolean | string,
|
||||||
simulationState: null as string | null | undefined,
|
simulationState: null as string | null | undefined,
|
||||||
simulationQueneLength: 0 as number,
|
simulationQueueLength: 0 as number | null | undefined,
|
||||||
currentLocation: null as CurrentLocation | null,
|
currentLocation: null as CurrentLocation | null | undefined,
|
||||||
nextLocation: null as NextLocation | null,
|
nextLocation: null as NextLocation | null,
|
||||||
messageList: [''] as string[],
|
messageList: [''] as string[],
|
||||||
errorList: [] as ErrorFull[],
|
errorList: [] as ErrorFull[],
|
||||||
locationQueue: [] as LocationQueue[],
|
locationQueueData: {} as LocationQueue,
|
||||||
leafLetZoom: 10 as number,
|
locationQueueOrder: [] as string[],
|
||||||
|
leafletZoom: 10 as number,
|
||||||
|
icloudMonitor: false as boolean,
|
||||||
|
findMyUpdate: null as FindMyUpdate | null | undefined,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
sockState: (state) => state.sockConnected,
|
sockState: (state) => state.sockConnected,
|
||||||
deviceState: (state) => state.deviceConnected,
|
deviceState: (state) => state.deviceConnected,
|
||||||
markerLatLng: (state) => {
|
lMarkerLatLng: (state): [number, number] => {
|
||||||
return [state.currentLocation.latitude, state.currentLocation.longitude]
|
if (
|
||||||
|
state.currentLocation == null ||
|
||||||
|
!state.currentLocation.latitude ||
|
||||||
|
!state.currentLocation.longitude
|
||||||
|
) {
|
||||||
|
return [0, 0];
|
||||||
|
}
|
||||||
|
return [state.currentLocation.latitude, state.currentLocation.longitude];
|
||||||
},
|
},
|
||||||
center(): [number, number] {
|
lCenter(): [number, number] {
|
||||||
return this.leafletCurrentMarker
|
return this.lMarkerLatLng;
|
||||||
},
|
},
|
||||||
zoom: (state) => state.leafletZoom,
|
lZoom: (state): number => state.leafletZoom,
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setSockStatus() {
|
setSockStatus() {
|
||||||
@@ -54,9 +67,13 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
socket.on('connect', () => {
|
socket.on('connect', () => {
|
||||||
this.setSockStatus();
|
this.setSockStatus();
|
||||||
socket.emit('message', 'Hello from client', (e: boolean) => {
|
socket.emit('message', 'Hello from client', (e: boolean) => {
|
||||||
console.log('Message delivered: ' + e);
|
if (debugLog) {
|
||||||
|
console.log('Message delivered: ' + e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
console.log('Connected to server');
|
if (debugLog) {
|
||||||
|
console.log('Connected to server');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
@@ -67,31 +84,79 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
socket.on('message', (e: string) => {
|
socket.on('message', (e: string) => {
|
||||||
this.setSockStatus();
|
this.setSockStatus();
|
||||||
this.messageList.push(e);
|
this.messageList.push(e);
|
||||||
console.log('Websock message received!');
|
if (debugLog) {
|
||||||
|
console.log('Websock message received!');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('error', (data: ErrorFull) => {
|
socket.on('error', (data: ErrorFull) => {
|
||||||
this.setSockStatus();
|
this.setSockStatus();
|
||||||
const errorFull = { type: data.type, error: data.error };
|
const errorFull = { type: data.type, error: data.error };
|
||||||
this.errorList.push(errorFull);
|
this.errorList.push(errorFull);
|
||||||
|
console.error('Error Received: ', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('status', (data: StatusUpdate): void => {
|
socket.on('status', (data: StatusUpdate): void => {
|
||||||
console.log("StatusUpdate received: ", data);
|
if (debugLog) {
|
||||||
this.simulationRunning = data.simulation_active;
|
console.log('StatusUpdate received: ', data);
|
||||||
this.simulationState = data.queue_state;
|
}
|
||||||
this.simulationQueneLength = data.quene_length;
|
this.digestUpdate(data);
|
||||||
this.tunnelConnected = !!data.tunnel;
|
});
|
||||||
this.currentLocation = { loc_id: data.loc_id, latitude: data.latitude, longitude: data.longitude, next_move: data.next_mode };
|
|
||||||
|
socket.on('fmf_update', (data: FindMyUpdate): void => {
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('event: fmf_update received: ', data);
|
||||||
|
}
|
||||||
|
this.findMyUpdate = data;
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('icloud_2fa_request', (callback) => {
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('iCloud 2FA Request');
|
||||||
|
}
|
||||||
|
$q.dialog({
|
||||||
|
component: iCloudCodeDialog,
|
||||||
|
})
|
||||||
|
.onOk((code: number) => {
|
||||||
|
if (callback && typeof callback === 'function') {
|
||||||
|
callback(code);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onCancel(() => {
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('Dialog cancelled');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onDismiss(() => {
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('Dialog dismissed');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.onAny((eventName, ...args) => {
|
socket.onAny((eventName, ...args) => {
|
||||||
this.setSockStatus();
|
console.log('Event received: ', eventName, ' Args: ', args, '');
|
||||||
console.log(`Received event: ${eventName}`, args);
|
/* if (serverToClientKnownEvents.includes(eventName)) {
|
||||||
|
console.log('Known event received: ', eventName, ' Args: ', args, '');
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
'Known events: ',
|
||||||
|
serverToClientKnownEvents,
|
||||||
|
' Received Event: ',
|
||||||
|
eventName,
|
||||||
|
' Args: ',
|
||||||
|
args,
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
console.log(`Received UNKNOWN Event: ${eventName}`, args);
|
||||||
|
}
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
connect() {
|
connect() {
|
||||||
console.log('Connecting to server...');
|
if (debugLog) {
|
||||||
|
console.log('Connecting to server...');
|
||||||
|
}
|
||||||
socket.connect();
|
socket.connect();
|
||||||
this.setSockStatus();
|
this.setSockStatus();
|
||||||
},
|
},
|
||||||
@@ -108,63 +173,202 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
}
|
}
|
||||||
this.setSockStatus();
|
this.setSockStatus();
|
||||||
},
|
},
|
||||||
setSimulationRunning(isRunning: boolean, states: string ): void {
|
setSimulationRunning(isRunning: boolean, states: string): void {
|
||||||
this.setSockStatus();
|
this.setSockStatus();
|
||||||
this.simulationState = states;
|
this.simulationState = states;
|
||||||
this.simulationRunning = isRunning;
|
this.simulationRunning = isRunning;
|
||||||
},
|
},
|
||||||
simulationControl(command: SimulationCommands, delay?: number, latitude?: number | null, longitude?: number | null): string | never {
|
icloudMonitorControl(command: string) {
|
||||||
|
let fnctRtn: { sts: string; msg?: string | undefined } = { sts: '', msg: '' };
|
||||||
|
switch (command) {
|
||||||
|
case 'start':
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('socketStore: got command: icloudMonitor start');
|
||||||
|
}
|
||||||
|
if (this.icloudMonitor) {
|
||||||
|
fnctRtn = { sts: 'error', msg: 'iCloud Monitor is already running' };
|
||||||
|
throw new Error('iCloud Monitor is already running');
|
||||||
|
}
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('Emitting icloud_monitor_control: start');
|
||||||
|
}
|
||||||
|
socket.emit(
|
||||||
|
'icloud_monitor_control',
|
||||||
|
{ command: 'start' },
|
||||||
|
(response: iCloudMonitorResponse) => {
|
||||||
|
fnctRtn.sts = response.status;
|
||||||
|
if (response.status == 'error') {
|
||||||
|
if (response.message) {
|
||||||
|
if (debugLog) {
|
||||||
|
console.log(response.message);
|
||||||
|
}
|
||||||
|
fnctRtn.msg = response.message;
|
||||||
|
} else {
|
||||||
|
fnctRtn.msg = 'Error';
|
||||||
|
}
|
||||||
|
throw new Error(fnctRtn.msg);
|
||||||
|
} else {
|
||||||
|
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
|
||||||
|
this.icloudMonitor = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'stop':
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('socketStore: got command: icloudMonitor stop');
|
||||||
|
}
|
||||||
|
if (!this.icloudMonitor) {
|
||||||
|
fnctRtn = { sts: 'error', msg: 'iCloud Monitor is not running' };
|
||||||
|
throw new Error('iCloud Monitor is not running');
|
||||||
|
}
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('Emitting icloud_monitor_control: stop');
|
||||||
|
}
|
||||||
|
socket.emit(
|
||||||
|
'icloud_monitor_control',
|
||||||
|
{ command: 'stop' },
|
||||||
|
(response: iCloudMonitorResponse) => {
|
||||||
|
fnctRtn.sts = response.status;
|
||||||
|
if (response.status == 'error') {
|
||||||
|
if (response.message) {
|
||||||
|
if (debugLog) {
|
||||||
|
console.log(response.message);
|
||||||
|
}
|
||||||
|
fnctRtn.msg = response.message;
|
||||||
|
} else {
|
||||||
|
fnctRtn.msg = 'Error';
|
||||||
|
}
|
||||||
|
throw new Error(fnctRtn.msg);
|
||||||
|
} else {
|
||||||
|
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
|
||||||
|
this.icloudMonitor = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'status':
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('socketStore: got command: icloudMonitor status');
|
||||||
|
}
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('Emitting icloud_monitor_control: status');
|
||||||
|
}
|
||||||
|
socket.emit(
|
||||||
|
'icloud_monitor_control',
|
||||||
|
{ command: 'status' },
|
||||||
|
(response: iCloudMonitorResponse) => {
|
||||||
|
fnctRtn.sts = response.status;
|
||||||
|
if (response.status == 'error') {
|
||||||
|
if (response.message) {
|
||||||
|
if (debugLog) {
|
||||||
|
console.log(response.message);
|
||||||
|
}
|
||||||
|
fnctRtn.msg = response.message;
|
||||||
|
} else {
|
||||||
|
fnctRtn.msg = 'Error';
|
||||||
|
}
|
||||||
|
throw new Error(fnctRtn.msg);
|
||||||
|
} else {
|
||||||
|
fnctRtn = {
|
||||||
|
sts: 'OK',
|
||||||
|
msg:
|
||||||
|
'iCloud Monitor Enabled: ' +
|
||||||
|
response.icloud_monitor_enabled +
|
||||||
|
'iCloud Monitor Running: ' +
|
||||||
|
response.icloud_monitor_running
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.icloudMonitor = !!(response.icloud_monitor_enabled && response.icloud_monitor_running);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fnctRtn = { sts: 'error', msg: 'Invalid command' };
|
||||||
|
throw new Error('Invalid command');
|
||||||
|
}
|
||||||
|
return fnctRtn;
|
||||||
|
},
|
||||||
|
simulationControl(
|
||||||
|
command: string,
|
||||||
|
delay?: number,
|
||||||
|
latitude?: number | null,
|
||||||
|
longitude?: number | null,
|
||||||
|
) {
|
||||||
|
let fnctRtn: { sts: string; msg?: string | undefined } = { sts: '', msg: '' };
|
||||||
this.setSockStatus();
|
this.setSockStatus();
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'start':
|
case 'start':
|
||||||
console.log("socketStore: got command: start");
|
if (debugLog) {
|
||||||
if (this.simulationRunning || this.simulationState == "RUNNING" || this.simulationState == "PAUSED") {
|
console.log('socketStore: got command: start');
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.simulationRunning ||
|
||||||
|
this.simulationState == 'RUNNING' ||
|
||||||
|
this.simulationState == 'PAUSED'
|
||||||
|
) {
|
||||||
|
fnctRtn = { sts: 'error', msg: 'Simulation is already running' };
|
||||||
throw new Error('Simulation is already running' + this.simulationState);
|
throw new Error('Simulation is already running' + this.simulationState);
|
||||||
}
|
}
|
||||||
console.log("Emmitting simulation_control: start")
|
if (debugLog) {
|
||||||
socket.emit('simulation_control', { command: 'start', delay: 0, latitude: null, longitude: null}, (response: SimulationControlResponse) => {
|
console.log('Emitting simulation_control: start');
|
||||||
if (response.status == "error") {
|
}
|
||||||
throw new Error(response.message);
|
socket.emit(
|
||||||
} else {
|
'simulation_control',
|
||||||
this.simulationState = response.status;
|
{ command: 'start', delay: 0, latitude: null, longitude: null },
|
||||||
console.log(response.message);
|
(response: SimulationControlResponse) => {
|
||||||
return response.message;
|
if (response.status == 'error') {
|
||||||
}
|
fnctRtn = { sts: 'error', msg: response.message?.toString() };
|
||||||
});
|
throw new Error(response.message);
|
||||||
|
} else {
|
||||||
|
fnctRtn = { sts: 'OK', msg: response.message?.toString() };
|
||||||
|
this.simulationState = response.status;
|
||||||
|
if (debugLog) {
|
||||||
|
console.log(response.message);
|
||||||
|
}
|
||||||
|
// return response.message;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case 'pause':
|
case 'pause':
|
||||||
if (this.simulationState !== "RUNNING" ) {
|
if (this.simulationState !== 'RUNNING') {
|
||||||
throw new Error('Simulation is not running');
|
throw new Error('Simulation is not running');
|
||||||
}
|
}
|
||||||
socket.emit('simulation_control', { command: 'pause' }, (response: SimulationControlResponse) => {
|
socket.emit(
|
||||||
if (response.status === "error") {
|
'simulation_control',
|
||||||
throw new Error(response.message);
|
{ command: 'pause' },
|
||||||
} else {
|
(response: SimulationControlResponse) => {
|
||||||
this.simulationState = response.status;
|
if (response.status === 'error') {
|
||||||
console.log(response.message);
|
throw new Error(response.message);
|
||||||
return response.message;
|
} else {
|
||||||
}
|
this.simulationState = response.status;
|
||||||
});
|
if (debugLog) {
|
||||||
|
console.log(response.message);
|
||||||
|
}
|
||||||
|
return response.message;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case 'resume':
|
case 'resume':
|
||||||
if (this.simulationState !== "PAUSED") {
|
if (this.simulationState !== 'PAUSED') {
|
||||||
throw new Error('Simulation is not paused');
|
throw new Error('Simulation is not paused');
|
||||||
}
|
}
|
||||||
socket.emit('simulation_control', { command: 'resume' }, (response) => {
|
socket.emit('simulation_control', { command: 'resume' }, (response) => {
|
||||||
if (response.status == "error") {
|
if (response.status == 'error') {
|
||||||
throw new Error(response.message)
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.status;
|
||||||
console.log(response.message)
|
if (debugLog) {
|
||||||
return response.message
|
console.log(response.message);
|
||||||
|
}
|
||||||
|
return response.message;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'clear':
|
case 'clear':
|
||||||
if (this.simulationQueueLength== 0) {
|
if (this.simulationQueueLength == 0) {
|
||||||
throw new Error('Simulation queue is empty');
|
throw new Error('Simulation queue is empty');
|
||||||
}
|
}
|
||||||
if (this.simulationState == "STOPPED " || !this.simulationRunning) {
|
if (this.simulationState == 'STOPPED ' || !this.simulationRunning) {
|
||||||
throw new Error('Simulation is not running');
|
throw new Error('Simulation is not running');
|
||||||
}
|
}
|
||||||
socket.emit('simulation_control', { command: 'clear' }, (response) => {
|
socket.emit('simulation_control', { command: 'clear' }, (response) => {
|
||||||
@@ -172,13 +376,15 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.status;
|
||||||
console.log(response.message);
|
if (debugLog) {
|
||||||
|
console.log(response.message);
|
||||||
|
}
|
||||||
return response.message;
|
return response.message;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'end':
|
case 'end':
|
||||||
if (this.simulationState == "ENDED" || !this.simulationRunning) {
|
if (this.simulationState == 'ENDED' || !this.simulationRunning) {
|
||||||
throw new Error('Simulation is already ended');
|
throw new Error('Simulation is already ended');
|
||||||
}
|
}
|
||||||
socket.emit('simulation_control', { command: 'end' }, (response) => {
|
socket.emit('simulation_control', { command: 'end' }, (response) => {
|
||||||
@@ -186,41 +392,73 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.status;
|
||||||
console.log(response.message);
|
if (debugLog) {
|
||||||
|
console.log(response.message);
|
||||||
|
}
|
||||||
return response.message;
|
return response.message;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'add':
|
case 'add':
|
||||||
if (this.simulationState == "ENDED" || !this.simulationRunning) {
|
// if (this.simulationState == 'ENDED' || !this.simulationRunning) {
|
||||||
throw new Error('Simulation is not running');
|
// throw new Error('Simulation is not running');
|
||||||
|
// }
|
||||||
|
if (!latitude || !longitude) {
|
||||||
|
throw new Error('latitude or longitude not set');
|
||||||
}
|
}
|
||||||
if (!latitude || !longitude) {
|
socket.emit(
|
||||||
throw new Error ("latitude or longitude not set");
|
'simulation_control',
|
||||||
}
|
{ command: 'add', latitude: latitude, longitude: longitude, delay: delay },
|
||||||
socket.emit('simulation_control',{ command: 'add', latitude: latitude, longitude: longitude, delay: delay }, (response) => {
|
(response) => {
|
||||||
if (response.status == "error") {
|
if (response.status == 'error') {
|
||||||
throw new Error(response.message)
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.status;
|
||||||
console.log("response from simulate_control_add: ", response);
|
if (debugLog) {
|
||||||
const locMrk = {
|
console.log('response from simulate_control_add: ', response);
|
||||||
[response.loc_id]: {
|
}
|
||||||
loc_id: response.loc_id,
|
const locMrk = {
|
||||||
latitude: response.latitude,
|
[response.loc_id]: {
|
||||||
longitude: response.longitude,
|
loc_id: response.loc_id,
|
||||||
delay: response.delay,
|
latitude: response.latitude,
|
||||||
start_time: response.start_time,
|
longitude: response.longitude,
|
||||||
},
|
delay: response.delay,
|
||||||
};
|
start_time: response.start_time,
|
||||||
this.locationQueue.push(locMrk);
|
},
|
||||||
return response.message;
|
};
|
||||||
}
|
return response.message;
|
||||||
});
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
fnctRtn = { sts: 'error', msg: 'Invalid command' };
|
||||||
throw new Error('Invalid command');
|
throw new Error('Invalid command');
|
||||||
}
|
}
|
||||||
|
return fnctRtn;
|
||||||
|
},
|
||||||
|
requestUpdate(): void {
|
||||||
|
socket.emit('request_update', (response: StatusUpdate) => {
|
||||||
|
this.digestUpdate(response);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
digestUpdate(data: StatusUpdate): void {
|
||||||
|
this.deviceConnected = !!(data.udid && data.tunnel);
|
||||||
|
this.testMode = data.test_mode;
|
||||||
|
this.simulationRunning = data.simulation_queue.active;
|
||||||
|
this.simulationState = data.simulation_queue.state;
|
||||||
|
this.simulationQueueLength = data.simulation_queue.order.length;
|
||||||
|
this.tunnelConnected = !!data.tunnel;
|
||||||
|
this.icloudMonitor = data.icloud.monitor_enabled;
|
||||||
|
this.currentLocation = {
|
||||||
|
loc_id: data.current_location.loc_id,
|
||||||
|
latitude: data.current_location.latitude,
|
||||||
|
longitude: data.current_location.longitude,
|
||||||
|
next_move: data.next_move,
|
||||||
|
};
|
||||||
|
this.locationQueueData = data.simulation_queue.data;
|
||||||
|
this.locationQueueOrder = data.simulation_queue.order;
|
||||||
|
this.findMyUpdate = data.fmf_location;
|
||||||
},
|
},
|
||||||
setDeviceState(state: boolean) {
|
setDeviceState(state: boolean) {
|
||||||
this.deviceConnected = state;
|
this.deviceConnected = state;
|
||||||
|
|||||||
Reference in New Issue
Block a user