2018-06-25 18:29:57 +02:00
|
|
|
<template>
|
|
|
|
<v-app>
|
|
|
|
<v-toolbar
|
|
|
|
app
|
|
|
|
>
|
2018-07-17 16:37:46 +02:00
|
|
|
<router-link :to="{ name: 'Map' }" class="noLinkDecoration">
|
2018-06-25 18:29:57 +02:00
|
|
|
<v-toolbar-title v-text="title" class="ma-0"></v-toolbar-title>
|
|
|
|
</router-link>
|
|
|
|
<v-spacer></v-spacer>
|
2018-07-26 13:55:08 +02:00
|
|
|
<v-btn
|
|
|
|
v-if="unsentReportsLength > 0"
|
|
|
|
icon
|
|
|
|
role="button"
|
|
|
|
:aria-label="$t('buttons.uploadUnsents')"
|
|
|
|
:loading="isSendingReports"
|
|
|
|
:disabled="isSendingReports"
|
|
|
|
class="mr-3"
|
|
|
|
color="orange"
|
|
|
|
dark
|
|
|
|
@click="sendUnsentReports"
|
|
|
|
>
|
|
|
|
<v-badge color="orange" left>
|
|
|
|
<span slot="badge">{{ unsentReportsLength }}</span>
|
|
|
|
<v-icon>cloud_upload</v-icon>
|
|
|
|
</v-badge>
|
|
|
|
</v-btn>
|
2018-07-21 20:00:37 +02:00
|
|
|
<v-menu offset-y class="menu" v-if="$route.name === 'Onboarding' || $route.name === 'Map' || $route.name === 'SharedMap'">
|
2018-07-11 01:14:54 +02:00
|
|
|
<v-btn slot="activator" icon role="button" :aria-label="$t('buttons.menu')">
|
2018-06-25 18:29:57 +02:00
|
|
|
<v-icon>more_vert</v-icon>
|
|
|
|
</v-btn>
|
|
|
|
<v-list>
|
2018-08-03 16:53:15 +02:00
|
|
|
<v-list-tile @click="exportGPX" v-if="isExportGPXMenuEntryVisible">
|
|
|
|
<v-list-tile-title>{{ $t("menu.exportGPX") }}</v-list-tile-title>
|
|
|
|
</v-list-tile>
|
2018-07-21 20:00:37 +02:00
|
|
|
<v-list-tile @click="isShareMapViewModalShown = true" v-if="isShareMapViewMenuEntryVisible">
|
|
|
|
<v-list-tile-title>{{ $t("menu.shareMapView") }}</v-list-tile-title>
|
2018-06-28 14:40:56 +02:00
|
|
|
</v-list-tile>
|
|
|
|
<v-list-tile @click="goToAbout">
|
|
|
|
<v-list-tile-title>{{ $t("menu.About") }}</v-list-tile-title>
|
|
|
|
</v-list-tile>
|
|
|
|
<v-list-tile @click="goToSettings">
|
|
|
|
<v-list-tile-title>{{ $t("menu.Settings") }}</v-list-tile-title>
|
2018-06-25 18:29:57 +02:00
|
|
|
</v-list-tile>
|
|
|
|
</v-list>
|
|
|
|
</v-menu>
|
2018-07-21 20:00:37 +02:00
|
|
|
<v-btn icon role="button" :aria-label="$t('buttons.back')" v-else @click="goBack">
|
|
|
|
<v-icon>arrow_back</v-icon>
|
|
|
|
</v-btn>
|
2018-07-04 18:20:28 +02:00
|
|
|
<div>
|
|
|
|
<v-progress-linear v-if="isLoading" :indeterminate="true" class="progressBar"></v-progress-linear>
|
|
|
|
</div>
|
2018-06-25 18:29:57 +02:00
|
|
|
</v-toolbar>
|
|
|
|
<v-content>
|
2018-07-26 13:55:08 +02:00
|
|
|
<ReportErrorModal v-model="hasReportError"></ReportErrorModal>
|
2018-07-21 20:00:37 +02:00
|
|
|
<ShareMapViewModal v-model="isShareMapViewModalShown"></ShareMapViewModal>
|
|
|
|
<router-view></router-view>
|
2018-06-25 18:29:57 +02:00
|
|
|
</v-content>
|
|
|
|
</v-app>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
2018-08-03 16:53:15 +02:00
|
|
|
import FileSaver from 'file-saver';
|
|
|
|
import createGPX from 'gps-to-gpx';
|
|
|
|
import moment from 'moment';
|
|
|
|
|
|
|
|
import { DELAY_BETWEEN_API_BATCH_REQUESTS, VERSION } from '@/constants';
|
2018-07-26 13:55:08 +02:00
|
|
|
|
|
|
|
import ReportErrorModal from '@/components/ReportErrorModal.vue';
|
2018-07-21 20:00:37 +02:00
|
|
|
import ShareMapViewModal from '@/components/ShareMapViewModal.vue';
|
|
|
|
|
2018-06-25 18:29:57 +02:00
|
|
|
export default {
|
2018-07-21 20:00:37 +02:00
|
|
|
components: {
|
2018-07-26 13:55:08 +02:00
|
|
|
ReportErrorModal,
|
2018-07-21 20:00:37 +02:00
|
|
|
ShareMapViewModal,
|
|
|
|
},
|
2018-07-04 18:20:28 +02:00
|
|
|
computed: {
|
|
|
|
isLoading() {
|
|
|
|
return this.$store.state.isLoading;
|
|
|
|
},
|
2018-08-03 16:53:15 +02:00
|
|
|
isExportGPXMenuEntryVisible() {
|
|
|
|
return this.$store.state.location.gpx.length > 0;
|
|
|
|
},
|
2018-07-21 20:00:37 +02:00
|
|
|
isShareMapViewMenuEntryVisible() {
|
|
|
|
return this.$store.state.map.center.every(item => item !== null);
|
|
|
|
},
|
2018-07-26 13:55:08 +02:00
|
|
|
unsentReportsLength() {
|
|
|
|
return this.$store.state.unsentReports.length;
|
|
|
|
},
|
2018-07-04 18:20:28 +02:00
|
|
|
},
|
2018-06-25 18:29:57 +02:00
|
|
|
data() {
|
|
|
|
return {
|
2018-07-26 13:55:08 +02:00
|
|
|
hasReportError: false,
|
|
|
|
isSendingReports: false,
|
2018-07-21 20:00:37 +02:00
|
|
|
isShareMapViewModalShown: false,
|
|
|
|
title: "Cycl'Assist",
|
2018-06-25 18:29:57 +02:00
|
|
|
};
|
|
|
|
},
|
|
|
|
methods: {
|
2018-08-03 16:53:15 +02:00
|
|
|
exportGPX() {
|
|
|
|
const activityName = this.$t('misc.activityName');
|
2018-08-09 23:46:01 +02:00
|
|
|
|
|
|
|
const courseKey = 'heading';
|
|
|
|
const eleKey = 'elevation';
|
|
|
|
const hdopKey = 'hdop';
|
|
|
|
const speedKey = 'speed';
|
|
|
|
const vdopKey = 'vdop';
|
|
|
|
|
2018-08-06 23:28:47 +02:00
|
|
|
const waypoints = [];
|
|
|
|
this.$store.state.location.gpx.forEach((item) => {
|
|
|
|
const waypoint = Object.assign({}, item, { timestamp: new Date(item.timestamp) });
|
2018-08-09 23:46:01 +02:00
|
|
|
[courseKey, eleKey, hdopKey, speedKey, vdopKey].forEach((key) => {
|
|
|
|
if (waypoint[key] === null || waypoint[key] === undefined) {
|
2018-08-20 13:57:14 +02:00
|
|
|
delete waypoint[key];
|
2018-08-09 23:46:01 +02:00
|
|
|
}
|
|
|
|
});
|
2018-08-06 23:28:47 +02:00
|
|
|
waypoints.push(waypoint);
|
|
|
|
});
|
2018-08-03 16:53:15 +02:00
|
|
|
const gpx = createGPX(waypoints, {
|
|
|
|
activityName,
|
|
|
|
creator: `Cycl'Assist v${VERSION}`,
|
2018-08-09 23:46:01 +02:00
|
|
|
courseKey,
|
|
|
|
eleKey,
|
|
|
|
hdopKey,
|
2018-08-03 16:53:15 +02:00
|
|
|
latKey: 'latitude',
|
|
|
|
lonKey: 'longitude',
|
2018-08-09 23:46:01 +02:00
|
|
|
speedKey,
|
2018-08-03 16:53:15 +02:00
|
|
|
startTime: waypoints[0].timestamp,
|
|
|
|
timeKey: 'timestamp',
|
2018-08-09 23:46:01 +02:00
|
|
|
vdopKey,
|
2018-08-03 16:53:15 +02:00
|
|
|
});
|
|
|
|
FileSaver.saveAs(
|
|
|
|
new Blob([gpx], { type: 'application/gpx+xml;charset=utf-8' }),
|
|
|
|
`cyclassist_${moment().locale('en').format('YYYY-MM-DD_HH-mm_ddd')}.gpx`,
|
|
|
|
);
|
|
|
|
},
|
2018-06-25 18:29:57 +02:00
|
|
|
goToAbout() {
|
|
|
|
this.$router.push({ name: 'About' });
|
|
|
|
},
|
2018-07-21 20:00:37 +02:00
|
|
|
goBack() {
|
|
|
|
this.$router.go(-1);
|
2018-06-28 14:40:56 +02:00
|
|
|
},
|
|
|
|
goToSettings() {
|
|
|
|
this.$router.push({ name: 'Settings' });
|
|
|
|
},
|
2018-07-26 13:55:08 +02:00
|
|
|
sendUnsentReports() {
|
|
|
|
if (!this.unsentReportsLength) {
|
|
|
|
this.isSendingReports = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.isSendingReports = true;
|
|
|
|
|
|
|
|
const index = this.unsentReportsLength - 1;
|
|
|
|
const report = this.$store.state.unsentReports[index];
|
|
|
|
this.$store.dispatch('saveReport', report)
|
|
|
|
.then(() => {
|
|
|
|
this.$store.dispatch('removeUnsentReport', { index });
|
|
|
|
this.hasReportError = false;
|
|
|
|
setTimeout(this.sendUnsentReports, DELAY_BETWEEN_API_BATCH_REQUESTS);
|
|
|
|
})
|
|
|
|
.catch((exc) => {
|
|
|
|
console.error(exc);
|
|
|
|
this.hasReportError = true;
|
|
|
|
this.isSendingReports = false;
|
|
|
|
});
|
|
|
|
},
|
2018-06-25 18:29:57 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
.menu {
|
|
|
|
z-index: 2000 !important;
|
|
|
|
}
|
|
|
|
|
|
|
|
.noLinkDecoration {
|
|
|
|
color: rgba(0, 0, 0, .87);
|
|
|
|
text-decoration: none;
|
|
|
|
}
|
2018-07-04 18:20:28 +02:00
|
|
|
|
|
|
|
.progressBar {
|
|
|
|
margin: 0;
|
|
|
|
position: absolute;
|
|
|
|
bottom: 0;
|
|
|
|
left: 0;
|
|
|
|
}
|
2018-06-25 18:29:57 +02:00
|
|
|
</style>
|
2018-06-27 11:21:29 +02:00
|
|
|
|
|
|
|
<style>
|
2018-07-03 19:54:32 +02:00
|
|
|
body, html, .application {
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
.application--wrap {
|
|
|
|
min-height: 100% !important;
|
|
|
|
}
|
|
|
|
|
2018-06-27 11:21:29 +02:00
|
|
|
.bottom-sheet.dialog {
|
|
|
|
webkit-transition: .1s cubic-bezier(.25, .8, .5, 1);
|
|
|
|
transition: .1s cubic-bezier(.25, .8, .5, 1);
|
|
|
|
}
|
|
|
|
</style>
|