Skip to content

Commit

Permalink
Merge pull request #149 from PokemonGoers/notifications
Browse files Browse the repository at this point in the history
PokeMob notifications
  • Loading branch information
Jochen Hartl authored Oct 27, 2016
2 parents ae9b505 + 29ae5ba commit 90e5a9b
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 10 deletions.
1 change: 1 addition & 0 deletions ionic2/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,5 @@
<plugin name="cordova-plugin-console" spec="~1.0.4" />
<plugin name="cordova-plugin-statusbar" spec="~2.1.3" />
<plugin name="cordova-plugin-device" spec="~1.1.3" />
<plugin name="de.appplant.cordova.plugin.local-notification" spec="~0.8.4" />
</widget>
2 changes: 2 additions & 0 deletions ionic2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@ionic/app-scripts": "0.0.37",
"@ionic/storage": "^1.1.6",
"@types/hammerjs": "^2.0.33",
"@types/socket.io-client": "^1.4.27",
"cordova": "^6.3.1",
"hammerjs": "^2.0.8",
"ionic": "^2.1.1",
Expand All @@ -33,6 +34,7 @@
"pokemap-2": "^0.2.2",
"rollup-plugin-replace": "^1.1.1",
"rxjs": "5.0.0-beta.12",
"socket.io-client": "^1.5.0",
"typescript": "^2.0.3",
"zone.js": "0.6.21"
},
Expand Down
22 changes: 15 additions & 7 deletions ionic2/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { Component, ViewChild } from '@angular/core';
import { Platform, Nav } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import 'rxjs/add/operator/map';

import { MapPage } from '../pages/map/map.page';
import { NotificationService } from '../services/notification.service';

@Component({
templateUrl: './app.html'
})
export class App {
rootPage = MapPage;

constructor(private platform: Platform) {
@ViewChild('content') nav: Nav;

constructor(private platform: Platform, private notificationService: NotificationService) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
Splashscreen.hide();
if (platform.is('cordova')) {
StatusBar.styleDefault();
Splashscreen.hide();
}

if (platform.is('android') && !platform.is('mobileweb')) {
notificationService.setNav(this.nav);
notificationService.scheduleNotifications();
}
});
}
}
4 changes: 4 additions & 0 deletions ionic2/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { ConfigService } from '../services/config.service';
import { LocationService } from '../services/location.service';
import { FilterService } from '../services/filter.service';
import { ProjectGroupsService } from '../services/project-groups.service';
import { WebsocketService } from '../services/websocket.service';
import { NotificationService } from '../services/notification.service';
import { TypeService } from '../services/type.service';

import { PokemonFilterPipe } from '../pipes/pokemon-filter/pokemon-filter.pipe';
Expand Down Expand Up @@ -78,6 +80,8 @@ for (let envKey in env) {
FilterService,
LocationService,
ProjectGroupsService,
WebsocketService,
NotificationService,
TypeService
]
})
Expand Down
3 changes: 2 additions & 1 deletion ionic2/src/models/mob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export class Mob extends POI {
clusterId: number;
tweets: MobTweet[];
timestamp: number;

coordinates: [number, number]; // [longitude, latitude]
isMob: boolean;
type = 'mob';
}

Expand Down
31 changes: 29 additions & 2 deletions ionic2/src/services/api.service.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { Injectable } from '@angular/core';
import { Http, Response, URLSearchParams } from '@angular/http';
import { Geolocation } from 'ionic-native';
import { Observable } from 'rxjs';

import { Pokemon, PokemonGender, PokemonAttackCategory } from '../models/pokemon';
import { Sighting } from '../models/sighting';
import { ConfigService } from './config.service';
import { WebsocketService } from './websocket.service';

@Injectable()
export class ApiService {

apiEndpoint: string;
private apiEndpoint: string;
private initializeMobSettings: Promise<any> = null;
private MOB_RADIUS: number = 5000000;

constructor(private http: Http, config: ConfigService) {

constructor(private http: Http, private websocket: WebsocketService, config: ConfigService) {
this.apiEndpoint = config.apiEndpoint;
}

Expand Down Expand Up @@ -269,4 +274,26 @@ export class ApiService {
return request.map(ApiService.handleResponse(Sighting));
}

/**
* Registers a callback which is called on every mob detection.
* @param {function} callback
*/
subscribeToMobs(callback: ((Mob) => any)) {
if (!this.initializeMobSettings) {
this.initializeMobSettings = Geolocation.getCurrentPosition()
.then(position => {
this.websocket.emit('settings', {
mode: 'geo',
lat: position.coords.latitude,
lon: position.coords.longitude,
radius: this.MOB_RADIUS
});
});
}

this.initializeMobSettings.then(() => {
this.websocket.on('mob', callback);
})
}

}
60 changes: 60 additions & 0 deletions ionic2/src/services/notification.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Injectable } from '@angular/core';
import { Nav } from 'ionic-angular';
import { LocalNotifications } from 'ionic-native';

import { Mob } from '../models/mob';
import { MapPage } from '../pages/map/map.page';
import { ApiService } from './api.service';

@Injectable()
export class NotificationService {

private MOB_NOTIFICATION_ID = 1;
private MOB_ZOOM_LEVEL = 15;

private nav: Nav;

constructor(private apiService: ApiService) {}

setNav(nav: Nav) {
this.nav = nav;
}

scheduleNotifications() {
this.apiService.subscribeToMobs(this.showMobNotification.bind(this));

LocalNotifications.on('click', notification => {
switch(notification.id) {
case this.MOB_NOTIFICATION_ID:
this.onMobNotificationClick(JSON.parse(notification.data));
break;
}
});
}

showMobNotification(mob: Mob) {
// https://github.com/katzer/cordova-plugin-local-notifications/wiki/04.-Scheduling
LocalNotifications.schedule({
id: this.MOB_NOTIFICATION_ID,
title: 'PredictEmAll - PokeMob detected',
text: mob.tweets.length + ' tweets about Pokémon were posted in your area',
icon: 'res://icon.png',
smallIcon: 'res://icon.png',
data: mob
});
}

onMobNotificationClick(mob: Mob) {
let parameters: any = {};
parameters.position = {
coordinates: {
latitude: mob.coordinates[1],
longitude: mob.coordinates[0]
},
zoomLevel: this.MOB_ZOOM_LEVEL
};

this.nav.setRoot(MapPage, parameters);
}

}
30 changes: 30 additions & 0 deletions ionic2/src/services/websocket.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as io from 'socket.io-client';
import { Injectable } from '@angular/core';
import { ConfigService } from './config.service';

@Injectable()
export class WebsocketService {

private connected: Promise<any>;

constructor(config: ConfigService) {
let socket: any = io.connect(config.websocketEndpoint);

this.connected = new Promise((resolve, reject) => {
socket.on('connect', () => resolve(socket));
});
}

on(key: string, callback: ((any) => any)) {
this.connected.then(socket => {
socket.on(key, callback);
});
}

emit(key: string, data: any) {
this.connected.then(socket => {
socket.emit(key, data);
})
}

}

0 comments on commit 90e5a9b

Please sign in to comment.