diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1762927..e24f342 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -12,13 +12,15 @@ import {AgmCoreModule} from "@agm/core"; import {MaterialModule} from "./material.module"; import {CalibrateComponent} from "./map/calibrate/calibrate.component"; import {MatInputModule} from "@angular/material"; +import {PermissionsComponent} from "./permissions/permissions.component"; @NgModule({ declarations: [ AppComponent, CalibrateComponent, HomeComponent, - MapComponent + MapComponent, + PermissionsComponent ], imports: [ AgmCoreModule.forRoot({apiKey: 'AIzaSyDFtvCY6nH_HUoTBNf_5b-E8nRweSLYtxE'}), @@ -31,7 +33,7 @@ import {MatInputModule} from "@angular/material"; MatInputModule, ], providers: [], - entryComponents: [CalibrateComponent], + entryComponents: [CalibrateComponent, PermissionsComponent], bootstrap: [AppComponent] }) export class AppModule { diff --git a/src/app/material.module.ts b/src/app/material.module.ts index 0e77e35..2038d84 100644 --- a/src/app/material.module.ts +++ b/src/app/material.module.ts @@ -1,6 +1,6 @@ import { MatBottomSheetModule, - MatButtonModule, MatDividerModule, MatFormFieldModule, + MatButtonModule, MatDialogModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatInputModule, MatMenuModule, MatSliderModule, MatSnackBarModule, MatToolbarModule @@ -10,6 +10,7 @@ import {NgModule} from "@angular/core"; export const materialModules = [ MatBottomSheetModule, MatButtonModule, + MatDialogModule, MatDividerModule, MatFormFieldModule, MatIconModule, diff --git a/src/app/permissions/permissions.component.html b/src/app/permissions/permissions.component.html new file mode 100644 index 0000000..ba55ffd --- /dev/null +++ b/src/app/permissions/permissions.component.html @@ -0,0 +1,10 @@ +
+
+
{{icon}}
+

{{message}}

+
+
+
+ + +
diff --git a/src/app/permissions/permissions.component.ts b/src/app/permissions/permissions.component.ts new file mode 100644 index 0000000..66f145c --- /dev/null +++ b/src/app/permissions/permissions.component.ts @@ -0,0 +1,16 @@ +import { Component, Inject } from "@angular/core"; +import { MAT_DIALOG_DATA } from "@angular/material"; + +@Component({ + selector: 'permissions', + templateUrl: 'permissions.component.html' +}) +export class PermissionsComponent { + icon: string; + message: string; + + constructor(@Inject(MAT_DIALOG_DATA) data) { + this.icon = data.icon; + this.message = data.message; + } +} diff --git a/src/app/permissions/permissions.service.ts b/src/app/permissions/permissions.service.ts new file mode 100644 index 0000000..1885563 --- /dev/null +++ b/src/app/permissions/permissions.service.ts @@ -0,0 +1,18 @@ +import {Injectable} from "@angular/core"; +import {MatDialog} from "@angular/material"; +import {PermissionsComponent} from "./permissions.component"; + +@Injectable({ + providedIn: 'root' +}) +export class PermissionsService { + constructor(private dialog: MatDialog) { } + + async requestPermission(name: string, icon: string, message: string) { + let perm = await navigator['permissions'].query({name: name}); + if (perm.state == 'prompt') { + return await this.dialog.open(PermissionsComponent, {autoFocus: false, data: {icon: icon, message: message}}).afterClosed().toPromise(); + } + return perm.state == 'granted' + } +} diff --git a/src/app/physics/physics.service.ts b/src/app/physics/physics.service.ts index 407fb51..d799b44 100644 --- a/src/app/physics/physics.service.ts +++ b/src/app/physics/physics.service.ts @@ -1,6 +1,7 @@ import {EventEmitter, Injectable} from '@angular/core'; import {BehaviorSubject, combineLatest} from "rxjs"; import {debounceTime} from "rxjs/operators"; +import {PermissionsService} from "../permissions/permissions.service"; @Injectable({ providedIn: 'root' @@ -17,53 +18,57 @@ export class PhysicsService { position = new BehaviorSubject(null); speed = new BehaviorSubject(null); - constructor() { - // Gather physical data - window.addEventListener('deviceorientation', orientation => this.orientation.next(orientation)); - window.addEventListener('devicemotion', motion => this.motion.next(motion)); - navigator.geolocation.watchPosition(position => this.position.next(position)); + constructor(permissionsService: PermissionsService) { + permissionsService.requestPermission('geolocation', 'gps_fixed', 'Can we use your location?').then(granted => { + if(granted) { + // Gather physical data + window.addEventListener('deviceorientation', orientation => this.orientation.next(orientation)); + window.addEventListener('devicemotion', motion => this.motion.next(motion)); + navigator.geolocation.watchPosition(position => this.position.next(position)); - // Calculate speed from motion events - this.motion.subscribe(event => { - if (!this.motionTimestamp) return this.motionTimestamp = new Date().getTime(); + // Calculate speed from motion events + this.motion.subscribe(event => { + if (!this.motionTimestamp) return this.motionTimestamp = new Date().getTime(); - let currentTime = new Date().getTime(); - let {speedX, speedY, speedZ} = this.speed.value || {speedX: 0, speedY: 0, speedZ: 0}; - this.speed.next({ - speedX: speedX + event.acceleration.x / 1000 * ((currentTime - this.motionTimestamp) / 1000) / 3600, - speedY: speedY + event.acceleration.y / 1000 * ((currentTime - this.motionTimestamp) / 1000) / 3600, - speedZ: speedZ + event.acceleration.z / 1000 * ((currentTime - this.motionTimestamp) / 1000) / 3600 - }); - this.motionTimestamp = currentTime; - }); + let currentTime = new Date().getTime(); + let {speedX, speedY, speedZ} = this.speed.value || {speedX: 0, speedY: 0, speedZ: 0}; + this.speed.next({ + speedX: speedX + event.acceleration.x / 1000 * ((currentTime - this.motionTimestamp) / 1000) / 3600, + speedY: speedY + event.acceleration.y / 1000 * ((currentTime - this.motionTimestamp) / 1000) / 3600, + speedZ: speedZ + event.acceleration.z / 1000 * ((currentTime - this.motionTimestamp) / 1000) / 3600 + }); + this.motionTimestamp = currentTime; + }); - // Combine data into one nice package - combineLatest(this.position, this.orientation, this.calibrate, this.speed).subscribe(data => { - if(!data[0]) return; + // Combine data into one nice package + combineLatest(this.position, this.orientation, this.calibrate, this.speed).subscribe(data => { + if(!data[0]) return; - let info = { - accuracy: data[0].coords.accuracy, - altitude: data[0].coords.altitude, - altitudeAccuracy: data[0].coords.altitudeAccuracy, - heading: data[0].coords.heading, - latitude: data[0].coords.latitude, - longitude: data[0].coords.longitude, - speed: data[0].coords.speed - }; + let info = { + accuracy: data[0].coords.accuracy, + altitude: data[0].coords.altitude, + altitudeAccuracy: data[0].coords.altitudeAccuracy, + heading: data[0].coords.heading, + latitude: data[0].coords.latitude, + longitude: data[0].coords.longitude, + speed: data[0].coords.speed + }; - if(info.heading == null && !!data[1] && data[1].alpha) { - if(!data[1].absolute && this.calibrate.value == null) { - this.requireCalibration.emit(); - this.calibrate.next(0); - } + if(info.heading == null && !!data[1] && data[1].alpha) { + if(!data[1].absolute && this.calibrate.value == null) { + this.requireCalibration.emit(); + this.calibrate.next(0); + } - info.heading = data[1].alpha + this.calibrate.value; - if(info.heading > 360) info.heading -= 360; - if(info.heading < 0) info.heading += 360; + info.heading = data[1].alpha + this.calibrate.value; + if(info.heading > 360) info.heading -= 360; + if(info.heading < 0) info.heading += 360; + } + if(info.speed == null && !!data[3]) info.speed = Math.sqrt(data[3].x**2 + data[3].y**2 + data[3].z**2); + + this.info.next(info); + }) } - if(info.speed == null && !!data[3]) info.speed = Math.sqrt(data[3].x**2 + data[3].y**2 + data[3].z**2); - - this.info.next(info); - }) + }); } }