├── mobile-app ├── .gitattributes ├── .bowerrc ├── ionic.project ├── resources │ ├── icon.png │ ├── splash.png │ ├── ios │ │ ├── icon │ │ │ ├── icon.png │ │ │ ├── icon-40.png │ │ │ ├── icon-50.png │ │ │ ├── icon-60.png │ │ │ ├── icon-72.png │ │ │ ├── icon-76.png │ │ │ ├── icon@2x.png │ │ │ ├── icon-40@2x.png │ │ │ ├── icon-50@2x.png │ │ │ ├── icon-60@2x.png │ │ │ ├── icon-60@3x.png │ │ │ ├── icon-72@2x.png │ │ │ ├── icon-76@2x.png │ │ │ ├── icon-small.png │ │ │ ├── icon-small@2x.png │ │ │ └── icon-small@3x.png │ │ └── splash │ │ │ ├── Default-667h.png │ │ │ ├── Default-736h.png │ │ │ ├── Default~iphone.png │ │ │ ├── Default@2x~iphone.png │ │ │ ├── Default-568h@2x~iphone.png │ │ │ ├── Default-Landscape-736h.png │ │ │ ├── Default-Landscape~ipad.png │ │ │ ├── Default-Portrait~ipad.png │ │ │ ├── Default-Portrait@2x~ipad.png │ │ │ └── Default-Landscape@2x~ipad.png │ └── android │ │ ├── icon │ │ ├── drawable-hdpi-icon.png │ │ ├── drawable-ldpi-icon.png │ │ ├── drawable-mdpi-icon.png │ │ ├── drawable-xhdpi-icon.png │ │ ├── drawable-xxhdpi-icon.png │ │ └── drawable-xxxhdpi-icon.png │ │ └── splash │ │ ├── drawable-land-hdpi-screen.png │ │ ├── drawable-land-ldpi-screen.png │ │ ├── drawable-land-mdpi-screen.png │ │ ├── drawable-port-hdpi-screen.png │ │ ├── drawable-port-ldpi-screen.png │ │ ├── drawable-port-mdpi-screen.png │ │ ├── drawable-land-xhdpi-screen.png │ │ ├── drawable-land-xxhdpi-screen.png │ │ ├── drawable-land-xxxhdpi-screen.png │ │ ├── drawable-port-xhdpi-screen.png │ │ ├── drawable-port-xxhdpi-screen.png │ │ └── drawable-port-xxxhdpi-screen.png ├── app │ ├── main │ │ ├── constants │ │ │ ├── env-dev.json │ │ │ ├── env-prod.json │ │ │ └── config-const.js │ │ ├── assets │ │ │ └── images │ │ │ │ └── yo@2x.png │ │ ├── controllers │ │ │ ├── main-ctrl.js │ │ │ ├── menu-ctrl.js │ │ │ ├── login-ctrl.js │ │ │ ├── ptc-auth-ctrl.js │ │ │ ├── google-auth-ctrl.js │ │ │ └── map-ctrl.js │ │ ├── templates │ │ │ ├── map.html │ │ │ ├── google-auth.html │ │ │ ├── ptc-auth.html │ │ │ ├── login.html │ │ │ └── menu.html │ │ ├── services │ │ │ └── main-serv.js │ │ ├── styles │ │ │ └── main.scss │ │ ├── main.js │ │ └── directives │ │ │ └── show-when.js │ ├── app.js │ ├── .eslintrc │ └── index.html ├── res │ ├── ios │ │ ├── set1 │ │ │ └── icon.png │ │ └── default │ │ │ └── icon.png │ └── android │ │ ├── set1 │ │ └── icon.png │ │ └── default │ │ └── icon.png ├── .eslintignore ├── test │ ├── protractor │ │ ├── .eslintrc │ │ └── main │ │ │ └── debug.spec.js │ └── karma │ │ ├── .eslintrc │ │ └── main │ │ ├── map-ctrl.spec.js │ │ ├── main-ctrl.spec.js │ │ ├── menu-ctrl.spec.js │ │ ├── login-ctrl.spec.js │ │ ├── ptc-auth-ctrl.spec.js │ │ ├── google-auth-ctrl.spec.js │ │ └── main-serv.spec.js ├── .gitignore ├── .travis.yml ├── .editorconfig ├── protractor.conf.js ├── .yo-rc.json ├── bower.json ├── hooks │ ├── README.md │ └── after_prepare │ │ └── update_platform_config.js ├── .eslintrc ├── gulp │ ├── linting.js │ ├── testing.js │ ├── utils │ │ └── Patcher.js │ ├── building.js │ ├── watching.js │ ├── cordova.js │ ├── configuring.js │ └── injecting.js ├── config.xml ├── package.json ├── jenkins.sh ├── karma.conf.js ├── gulpfile.js └── README.md ├── .gitignore ├── backend └── web_socket_server.py ├── LICENSE └── README.md /mobile-app/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /mobile-app/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /mobile-app/ionic.project: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mobile-app", 3 | "app_id": "" 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .mobile-app/platforms/ios/ 3 | .mobile-app/platforms/android/ 4 | .mobile-app/node_modules/ 5 | -------------------------------------------------------------------------------- /mobile-app/resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/icon.png -------------------------------------------------------------------------------- /mobile-app/app/main/constants/env-dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "SERVER_URL": "https://DEVSERVER/api", 3 | "SOME_OTHER_URL": "/proxy" 4 | } 5 | -------------------------------------------------------------------------------- /mobile-app/res/ios/set1/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/res/ios/set1/icon.png -------------------------------------------------------------------------------- /mobile-app/resources/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/splash.png -------------------------------------------------------------------------------- /mobile-app/res/ios/default/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/res/ios/default/icon.png -------------------------------------------------------------------------------- /mobile-app/res/android/set1/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/res/android/set1/icon.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon.png -------------------------------------------------------------------------------- /mobile-app/res/android/default/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/res/android/default/icon.png -------------------------------------------------------------------------------- /mobile-app/app/main/assets/images/yo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/app/main/assets/images/yo@2x.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-40.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-50.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-60.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-72.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-76.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon@2x.png -------------------------------------------------------------------------------- /mobile-app/app/main/constants/env-prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "SERVER_URL": "https://PRODSERVER/api", 3 | "SOME_OTHER_URL": "https://echo.getpostman.com" 4 | } 5 | -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-40@2x.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-50@2x.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-60@2x.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-60@3x.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-72@2x.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-76@2x.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-small.png -------------------------------------------------------------------------------- /mobile-app/app/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('pokemongoBot', [ 3 | // load your modules here 4 | 'main', // starting with the main module 5 | ]); 6 | -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-small@2x.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/icon/icon-small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/icon/icon-small@3x.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default-667h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default-667h.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default-736h.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default~iphone.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default@2x~iphone.png -------------------------------------------------------------------------------- /mobile-app/resources/android/icon/drawable-hdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/icon/drawable-hdpi-icon.png -------------------------------------------------------------------------------- /mobile-app/resources/android/icon/drawable-ldpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/icon/drawable-ldpi-icon.png -------------------------------------------------------------------------------- /mobile-app/resources/android/icon/drawable-mdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/icon/drawable-mdpi-icon.png -------------------------------------------------------------------------------- /mobile-app/resources/android/icon/drawable-xhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/icon/drawable-xhdpi-icon.png -------------------------------------------------------------------------------- /mobile-app/resources/android/icon/drawable-xxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/icon/drawable-xxhdpi-icon.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default-568h@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default-568h@2x~iphone.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default-Landscape-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default-Landscape-736h.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default-Landscape~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default-Landscape~ipad.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default-Portrait~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default-Portrait~ipad.png -------------------------------------------------------------------------------- /mobile-app/resources/android/icon/drawable-xxxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/icon/drawable-xxxhdpi-icon.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default-Portrait@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default-Portrait@2x~ipad.png -------------------------------------------------------------------------------- /mobile-app/resources/ios/splash/Default-Landscape@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/ios/splash/Default-Landscape@2x~ipad.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-land-hdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-land-hdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-land-ldpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-land-ldpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-land-mdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-land-mdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-port-hdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-port-hdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-port-ldpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-port-ldpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-port-mdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-port-mdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-land-xhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-land-xhdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-land-xxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-land-xxhdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-land-xxxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-land-xxxhdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-port-xhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-port-xhdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-port-xxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-port-xxhdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/resources/android/splash/drawable-port-xxxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokemonGoF/PokemonGo-Bot-Mobile/HEAD/mobile-app/resources/android/splash/drawable-port-xxxhdpi-screen.png -------------------------------------------------------------------------------- /mobile-app/.eslintignore: -------------------------------------------------------------------------------- 1 | # more info here - http://eslint.org/docs/user-guide/configuring.html#ignoring-files-and-directories 2 | 3 | # node_modules ignored by default 4 | 5 | # ignore bower_components 6 | app/bower_components 7 | -------------------------------------------------------------------------------- /mobile-app/test/protractor/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../app/.eslintrc", 3 | "env": { 4 | "jasmine": true, 5 | "protractor": true 6 | }, 7 | "globals": { 8 | }, 9 | "rules": { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /mobile-app/test/karma/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../app/.eslintrc", 3 | "env": { 4 | "jasmine": true 5 | }, 6 | "globals": { 7 | "inject": true, 8 | "module": true 9 | }, 10 | "rules": { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /mobile-app/app/main/controllers/main-ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('main') 3 | .controller('MainCtrl', function ($log) { 4 | 5 | $log.log('Hello from your Controller: MainCtrl in module main:. This is your controller:', this); 6 | 7 | }); 8 | -------------------------------------------------------------------------------- /mobile-app/app/main/controllers/menu-ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('main') 3 | .controller('MenuCtrl', function ($log) { 4 | 5 | $log.log('Hello from your Controller: MenuCtrl in module main:. This is your controller:', this); 6 | 7 | }); 8 | -------------------------------------------------------------------------------- /mobile-app/app/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.eslintrc", 3 | "env": { 4 | "node": false, 5 | "browser": true 6 | }, 7 | "globals": { 8 | "angular": true, 9 | "ionic": true, 10 | "localforage": true 11 | }, 12 | "rules": { 13 | "no-console": 1 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /mobile-app/app/main/templates/map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |
8 |
-------------------------------------------------------------------------------- /mobile-app/.gitignore: -------------------------------------------------------------------------------- 1 | # temp files 2 | .DS_Store 3 | .tmp 4 | .sass-cache 5 | 6 | # npm & bower 7 | /node_modules/ 8 | /app/bower_components/ 9 | 10 | # custom gulp settings 11 | /gulp/.gulp_settings.json 12 | 13 | # ionic fonts 14 | /app/main/assets/fonts/ionicons.* 15 | 16 | # cordova 17 | /platforms/ 18 | /plugins/ 19 | /res/*/current/ 20 | 21 | # build folder 22 | /www/** 23 | 24 | # IDE 25 | *.sublime-project 26 | *.sublime-workspace 27 | -------------------------------------------------------------------------------- /mobile-app/app/main/constants/config-const.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('main') 3 | .constant('Config', { 4 | 5 | // gulp environment: injects environment vars 6 | ENV: { 7 | /*inject-env*/ 8 | 'SERVER_URL': 'https://DEVSERVER/api', 9 | 'SOME_OTHER_URL': '/proxy' 10 | /*endinject*/ 11 | }, 12 | 13 | // gulp build-vars: injects build vars 14 | BUILD: { 15 | /*inject-build*/ 16 | /*endinject*/ 17 | } 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /mobile-app/app/main/controllers/login-ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('main') 3 | .controller('LoginCtrl', function ($log, $scope, $state) { 4 | 5 | $log.log('Hello from your Controller: LoginCtrl in module main:. This is your controller:', this); 6 | 7 | $scope.googleClicked = function () { 8 | $state.go('main.google-auth'); 9 | }; 10 | 11 | $scope.ptcClicked = function () { 12 | $state.go('main.ptc-auth'); 13 | }; 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /mobile-app/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: node_js 4 | node_js: 5 | - "6" 6 | - "5" 7 | - "4" 8 | # addons: 9 | # apt: 10 | # sources: 11 | # - google-chrome 12 | # packages: 13 | # - google-chrome-stable 14 | before_install: 15 | - npm install -g bower 16 | # - export DISPLAY=:99.0 17 | # - sh -e /etc/init.d/xvfb start 18 | # - sleep 3 # give xvfb some time to start 19 | install: 20 | - npm install 21 | - bower install 22 | -------------------------------------------------------------------------------- /mobile-app/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /mobile-app/test/karma/main/map-ctrl.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('module: main, controller: MapCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('main')); 7 | // load all the templates to prevent unexpected $http requests from ui-router 8 | beforeEach(module('ngHtml2Js')); 9 | 10 | // instantiate controller 11 | var MapCtrl; 12 | beforeEach(inject(function ($controller) { 13 | MapCtrl = $controller('MapCtrl'); 14 | })); 15 | 16 | it('should do something', function () { 17 | expect(!!MapCtrl).toBe(true); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /mobile-app/test/karma/main/main-ctrl.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('module: main, controller: MainCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('main')); 7 | // load all the templates to prevent unexpected $http requests from ui-router 8 | beforeEach(module('ngHtml2Js')); 9 | 10 | // instantiate controller 11 | var MainCtrl; 12 | beforeEach(inject(function ($controller) { 13 | MainCtrl = $controller('MainCtrl'); 14 | })); 15 | 16 | it('should do something', function () { 17 | expect(!!MainCtrl).toBe(true); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /mobile-app/test/karma/main/menu-ctrl.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('module: main, controller: MenuCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('main')); 7 | // load all the templates to prevent unexpected $http requests from ui-router 8 | beforeEach(module('ngHtml2Js')); 9 | 10 | // instantiate controller 11 | var MenuCtrl; 12 | beforeEach(inject(function ($controller) { 13 | MenuCtrl = $controller('MenuCtrl'); 14 | })); 15 | 16 | it('should do something', function () { 17 | expect(!!MenuCtrl).toBe(true); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /mobile-app/test/karma/main/login-ctrl.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('module: main, controller: LoginCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('main')); 7 | // load all the templates to prevent unexpected $http requests from ui-router 8 | beforeEach(module('ngHtml2Js')); 9 | 10 | // instantiate controller 11 | var LoginCtrl; 12 | beforeEach(inject(function ($controller) { 13 | LoginCtrl = $controller('LoginCtrl'); 14 | })); 15 | 16 | it('should do something', function () { 17 | expect(!!LoginCtrl).toBe(true); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /mobile-app/app/main/services/main-serv.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('main') 3 | .service('Main', function ($log, $timeout) { 4 | 5 | $log.log('Hello from your Service: Main in module main'); 6 | 7 | // some initial data 8 | this.someData = { 9 | binding: 'Yes! Got that databinding working' 10 | }; 11 | 12 | this.changeBriefly = function () { 13 | var initialValue = this.someData.binding; 14 | this.someData.binding = 'Yeah this was changed'; 15 | 16 | var that = this; 17 | $timeout(function () { 18 | that.someData.binding = initialValue; 19 | }, 500); 20 | }; 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /mobile-app/test/karma/main/ptc-auth-ctrl.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('module: main, controller: PtcAuthCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('main')); 7 | // load all the templates to prevent unexpected $http requests from ui-router 8 | beforeEach(module('ngHtml2Js')); 9 | 10 | // instantiate controller 11 | var PtcAuthCtrl; 12 | beforeEach(inject(function ($controller) { 13 | PtcAuthCtrl = $controller('PtcAuthCtrl'); 14 | })); 15 | 16 | it('should do something', function () { 17 | expect(!!PtcAuthCtrl).toBe(true); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /mobile-app/app/main/templates/google-auth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 9 | 13 |
14 | 17 | 18 |
19 |
20 | -------------------------------------------------------------------------------- /mobile-app/test/karma/main/google-auth-ctrl.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('module: main, controller: GoogleAuthCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('main')); 7 | // load all the templates to prevent unexpected $http requests from ui-router 8 | beforeEach(module('ngHtml2Js')); 9 | 10 | // instantiate controller 11 | var GoogleAuthCtrl; 12 | beforeEach(inject(function ($controller) { 13 | GoogleAuthCtrl = $controller('GoogleAuthCtrl'); 14 | })); 15 | 16 | it('should do something', function () { 17 | expect(!!GoogleAuthCtrl).toBe(true); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /mobile-app/protractor.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // An example configuration file. 4 | exports.config = { 5 | // The address of a running selenium server. 6 | //seleniumAddress: 'http://localhost:4444/wd/hub', 7 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json 8 | 9 | // Capabilities to be passed to the webdriver instance. 10 | capabilities: { 11 | 'browserName': 'chrome' 12 | }, 13 | 14 | baseUrl: 'http://localhost:3000', 15 | 16 | // Spec patterns are relative to the current working directly when 17 | // protractor is called. 18 | specs: ['test/protractor/**/*.js'], 19 | }; 20 | -------------------------------------------------------------------------------- /mobile-app/app/main/templates/ptc-auth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 9 | 13 |
14 | 17 | 18 |
19 |
20 | -------------------------------------------------------------------------------- /mobile-app/app/main/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /backend/web_socket_server.py: -------------------------------------------------------------------------------- 1 | import tornado 2 | from tornado import websocket, web, httpserver, ioloop 3 | import json 4 | 5 | cl = [] 6 | 7 | class SocketHandler(websocket.WebSocketHandler): 8 | def check_origin(self, origin): 9 | return True 10 | 11 | def open(self): 12 | if self not in cl: 13 | cl.append(self) 14 | 15 | def on_message(self, data): 16 | print 'Messaged received' 17 | print data 18 | 19 | def on_close(self): 20 | if self in cl: 21 | cl.remove(self) 22 | 23 | 24 | app = web.Application([ 25 | (r'/ws', SocketHandler) 26 | ]) 27 | 28 | if __name__ == '__main__': 29 | app.listen(5000) 30 | ioloop.IOLoop.instance().start() -------------------------------------------------------------------------------- /mobile-app/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-m-ionic": { 3 | "answers": { 4 | "appName": "PokemonGo-Bot", 5 | "appId": "com.pokemongof.pokemongobot", 6 | "ionicCss": false, 7 | "bowerPackages": [ 8 | "angular-dynamic-locale#~0.1.27", 9 | "angular-translate#~2.11.0", 10 | "angular-translate-loader-static-files#~2.11.0", 11 | "localforage#~1.4.0" 12 | ], 13 | "platforms": [ 14 | "ios", 15 | "android" 16 | ], 17 | "plugins": [ 18 | "cordova-plugin-device", 19 | "cordova-plugin-inappbrowser", 20 | "cordova-plugin-splashscreen", 21 | "cordova-plugin-statusbar" 22 | ], 23 | "appModule": "pokemongoBot", 24 | "ecosystems": [] 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /mobile-app/test/karma/main/main-serv.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('module: main, service: Main', function () { 4 | 5 | // load the service's module 6 | beforeEach(module('main')); 7 | // load all the templates to prevent unexpected $http requests from ui-router 8 | beforeEach(module('ngHtml2Js')); 9 | 10 | // instantiate service 11 | var Main; 12 | var $timeout; 13 | beforeEach(inject(function (_Main_, _$timeout_) { 14 | Main = _Main_; 15 | $timeout = _$timeout_; 16 | })); 17 | 18 | describe('.changeBriefly()', function () { 19 | beforeEach(function () { 20 | Main.changeBriefly(); 21 | }); 22 | it('should briefly change', function () { 23 | expect(Main.someData.binding).toEqual('Yeah this was changed'); 24 | $timeout.flush(); 25 | expect(Main.someData.binding).toEqual('Yes! Got that databinding working'); 26 | }); 27 | }); 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /mobile-app/app/main/controllers/ptc-auth-ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('main') 3 | .controller('PtcAuthCtrl', function ($log, $scope, $state, WebSocket, $ionicHistory, $ionicConfig) { 4 | 5 | $ionicHistory.nextViewOptions({ 6 | disableBack: true 7 | }); 8 | 9 | $ionicConfig.backButton.previousTitleText(false); 10 | $ionicConfig.backButton.icon('ion-chevron-left'); 11 | $ionicConfig.backButton.text(''); 12 | 13 | $log.log('Hello from your Controller: PtcAuthCtrl in module main:. This is your controller:', this); 14 | 15 | $scope.signIn = function (user) { 16 | this.username = user.username; 17 | this.password = user.password; 18 | this.auth = 'ptc'; 19 | 20 | // TODO: Authenticate here 21 | 22 | $scope.ws = WebSocket; 23 | $scope.ws.sendUser(this.auth, this.username, this.password); 24 | 25 | // If authentication is successful, go to Map view 26 | $state.go('main.map'); 27 | }; 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /mobile-app/app/main/controllers/google-auth-ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('main') 3 | .controller('GoogleAuthCtrl', function ($log, $scope, $state, WebSocket, $ionicHistory, $ionicConfig) { 4 | 5 | $ionicHistory.nextViewOptions({ 6 | disableBack: true 7 | }); 8 | 9 | $ionicConfig.backButton.previousTitleText(false); 10 | $ionicConfig.backButton.icon('ion-chevron-left'); 11 | $ionicConfig.backButton.text(''); 12 | 13 | $log.log('Hello from your Controller: GoogleAuthCtrl in module main:. This is your controller:', this); 14 | 15 | $scope.signIn = function (user) { 16 | this.email = user.username; 17 | this.password = user.password; 18 | this.auth = 'google'; 19 | 20 | // TODO: Authenticate here 21 | 22 | $scope.ws = WebSocket; 23 | $scope.ws.sendUser(this.auth, this.email, this.password); 24 | 25 | // If authentication is successful, go to Map view 26 | $state.go('main.map'); 27 | }; 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /mobile-app/test/protractor/main/debug.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Debug page', function () { 4 | 5 | beforeEach(function () { 6 | browser.get('/#/main/debug'); 7 | }); 8 | 9 | it('should grade passwords', function () { 10 | 11 | var passwordInput = element(by.model('ctrl.password.input')); 12 | var passwordStrength = element(by.binding('ctrl.password.strength')); 13 | 14 | // weak 15 | passwordInput.sendKeys('my'); 16 | expect(passwordStrength.getText()).toEqual('weak'); 17 | expect(passwordStrength.getAttribute('class')).toContain('badge-assertive'); 18 | 19 | // medium 20 | passwordInput.sendKeys('test'); 21 | expect(passwordStrength.getText()).toEqual('medium'); 22 | expect(passwordStrength.getAttribute('class')).toContain('badge-energized'); 23 | 24 | // strong 25 | passwordInput.sendKeys('tesyasdft'); 26 | expect(passwordStrength.getText()).toEqual('strong'); 27 | expect(passwordStrength.getAttribute('class')).toContain('badge-balanced'); 28 | 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /mobile-app/app/main/styles/main.scss: -------------------------------------------------------------------------------- 1 | /* 2 | To customize the look and feel of Ionic, you can override the variables 3 | in ionic's _variables.scss file. 4 | 5 | For example, you might change some of the default colors: 6 | */ 7 | 8 | $light: #fff !default; 9 | $stable: #f8f8f8 !default; 10 | $positive: #4a87ee !default; 11 | $calm: #43cee6 !default; 12 | $balanced: #66cc33 !default; 13 | $energized: #f0b840 !default; 14 | $assertive: #ef4e3a !default; 15 | $royal: #8a6de9 !default; 16 | $dark: #444 !default; 17 | 18 | // The path for our ionicons font files, relative to the built & temporary main.css 19 | $ionicons-font-path: "../assets/fonts" !default; 20 | 21 | // Include all of Ionic 22 | @import "../../bower_components/ionic/scss/ionic"; 23 | 24 | #map { 25 | width: 100%; 26 | height: 100%; 27 | } 28 | 29 | .scroll { 30 | height: 100%; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /mobile-app/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "ionic": "~1.3.0", 4 | "angular": "~1.5.0", 5 | "angular-animate": "~1.5.0", 6 | "angular-sanitize": "~1.5.0", 7 | "angular-ui-router": "~0.3.1", 8 | "ngCordova": "~0.1.17-alpha", 9 | "angular-dynamic-locale": "~0.1.27", 10 | "angular-translate": "~2.11.0", 11 | "angular-translate-loader-static-files": "~2.11.0", 12 | "localforage": "~1.4.0", 13 | "angular-local-storage": "~0.1.5", 14 | "angular-http-auth": "https://github.com/witoldsz/angular-http-auth.git#1.2.2", 15 | "lodash": "^4.14.0", 16 | "angular-websocket": "^2.0.0", 17 | "ion-md-input": "^1.0.4", 18 | "ionic-material": "^0.4.2" 19 | }, 20 | "devDependencies": { 21 | "angular-mocks": "~1.5.0" 22 | }, 23 | "resolutions": { 24 | "angular": "~1.5.0", 25 | "angular-animate": "~1.5.0", 26 | "angular-sanitize": "~1.5.0", 27 | "angular-ui-router": "~0.3.1", 28 | "angular-mocks": "~1.2.17", 29 | "angular-scenario": "~1.2.17" 30 | }, 31 | "name": "pokemongo-bot", 32 | "private": true 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /mobile-app/hooks/README.md: -------------------------------------------------------------------------------- 1 | 21 | # Cordova Hooks 22 | 23 | Cordova Hooks represent special scripts which could be added by application and plugin developers or even by your own build system to customize cordova commands. See Hooks Guide for more details: http://cordova.apache.org/docs/en/edge/guide_appdev_hooks_index.md.html#Hooks%20Guide. 24 | -------------------------------------------------------------------------------- /mobile-app/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "node": true 5 | }, 6 | "rules": { 7 | // overrides from 'recommended' 8 | "comma-dangle": 0, 9 | "no-console": 0, 10 | 11 | // strict 12 | "strict": [2, "global"], 13 | 14 | // formatting, spaces, operators 15 | "indent": [2, 2, {"SwitchCase": 1}], 16 | "quotes": [2, "single"], 17 | "semi": [2, "always"], 18 | "keyword-spacing": 2, 19 | "space-before-blocks": [2, "always"], 20 | "space-before-function-paren": [2, "always"], 21 | "dot-location": [2, "property"], 22 | "space-infix-ops": 2, 23 | "key-spacing": [2, {"beforeColon": false, "afterColon": true}], 24 | "operator-linebreak": [2, "after"], 25 | "no-spaced-func": 2, 26 | "comma-spacing": [1, {"before": false, "after": true}], 27 | "no-multiple-empty-lines": [2, {"max": 2}], 28 | "camelcase": [1, {"properties": "always"}], 29 | 30 | // coding style 31 | "curly": 2, 32 | "wrap-iife": [2, "inside"], 33 | "eqeqeq": 2, 34 | "no-use-before-define": [2, "nofunc"], 35 | "no-unused-vars": 2, 36 | "no-unexpected-multiline": 2, 37 | "no-multi-str": 2, 38 | "no-irregular-whitespace": 2, 39 | 40 | // os/git options 41 | "no-trailing-spaces": 2, 42 | "linebreak-style": 0, 43 | "eol-last": 2 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mobile-app/gulp/linting.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // gulp 3 | var gulp = require('gulp'); 4 | var paths = gulp.paths; 5 | // plugins 6 | var $ = require('gulp-load-plugins')(); 7 | 8 | // all linting tasks 9 | gulp.task('linting', ['eslint', 'jsonlint']); 10 | gulp.task('linting-throw', ['eslint-throw', 'jsonlint-throw']); 11 | 12 | // check app and test for eslint errors 13 | var eslint = function (fail) { 14 | return function () { 15 | return gulp.src(paths.jsFiles.concat(paths.karma).concat(paths.protractor)) 16 | .pipe($.eslint()) 17 | .pipe($.eslint.format()) 18 | .pipe($.if(fail, $.eslint.failOnError())); 19 | }; 20 | }; 21 | gulp.task('eslint', eslint()); 22 | gulp.task('eslint-throw', eslint(true)); 23 | 24 | // check app for jsonlint errors 25 | var jsonlint = function (fail) { 26 | var failReporter = function (file) { 27 | throw new Error(file.path + '\n' + file.jsonlint.message); 28 | }; 29 | return function () { 30 | return gulp.src(paths.jsonFiles) 31 | .pipe($.jsonlint()) 32 | .pipe($.jsonlint.reporter(fail ? failReporter : undefined)); 33 | }; 34 | }; 35 | gulp.task('jsonlint', jsonlint()); 36 | gulp.task('jsonlint-throw', jsonlint(true)); 37 | 38 | // eslint task for contributors 39 | gulp.task('contrib-linting', ['linting'], function () { 40 | return gulp.src(paths.contrib) 41 | .pipe($.eslint()) 42 | .pipe($.eslint.format()); 43 | }); 44 | -------------------------------------------------------------------------------- /mobile-app/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | PokemonGo-Bot 4 | 5 | A sample Apache Cordova application that responds to the deviceready event. 6 | 7 | 8 | Apache Cordova Team 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PokemonGo-Bot-Mobile 2 | 3 | The cross-platform (iOS, Android) mobile app for PokemonGo-Bot is a work in progress! 4 | 5 | ![Login Screen](http://i.imgur.com/wHYgnVQ.png?1) 6 | 7 | ## Installation 8 | Checkout this repository, then `cd` to it. 9 | - `cd PokemonGo-Bot-Mobile/mobile-app` 10 | - `npm install` 11 | - `bower install` 12 | - `gulp` to build and preview app in a web browser 13 | 14 | This project uses Ionic for programming the mobile app. The Ionic project files can be found in `PokemonGo-Bot-Mobile/mobile-app`. 15 | 16 | The backend architecture is currently undecided. However, a simple proof-of-concept for a Python websocket server can be found in `PokemonGo-Bot-Mobile/backend`. 17 | 18 | ## Testing on iOS/Android 19 | The skeleton code for this project was generated with [generator-m-ionic](https://github.com/mwaylabs/generator-m-ionic/). [See their development reference](https://github.com/mwaylabs/generator-m-ionic/blob/master/docs/guides/development_intro.md) for the list of the `gulp` commands to build & emulate/run the code on iOS and Android devices. See [Ionic's documentation & guide](http://ionicframework.com/docs/guide/) for details on how to use the Ionic framework. 20 | 21 | ## Development 22 | 23 | To contribute, fork this repo. Make all development changes to the branch `dev`. After you've committed your code changes, push to your fork repo and make a pull request. 24 | 25 | ## TODO: 26 | - [ ] Google Authentication 27 | - [ ] PTC Authentication 28 | - [ ] API to communicate with Python 29 | - [x] Google Map (the Google Maps API key included in index.html is for use in in development only on http://localhost) 30 | - [ ] Show sidemenu button & Google Map only when user is logged-in and authenticated 31 | -------------------------------------------------------------------------------- /mobile-app/app/main/templates/menu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | menu header 28 | 29 |

Navigation

30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | Map 42 |
43 |
44 | 45 |
46 | 47 | Logout 48 |
49 |
50 |
51 | 52 |
53 | 54 |
55 | -------------------------------------------------------------------------------- /mobile-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "engines": { 4 | "node": ">=4.0.0" 5 | }, 6 | "scripts": { 7 | "test": "gulp build --minify && gulp karma" 8 | }, 9 | "devDependencies": { 10 | "browser-sync": "^2.8.3", 11 | "chalk": "^1.1.0", 12 | "cordova": "^6.0.0", 13 | "del": "^2.0.0", 14 | "elementtree": "^0.1.6", 15 | "eslint": "^3.0.0", 16 | "gulp": "^3.9.0", 17 | "gulp-angular-filesort": "^1.1.1", 18 | "gulp-autoprefixer": "^3.0.1", 19 | "gulp-changed": "^1.3.0", 20 | "gulp-csso": "^2.0.0", 21 | "gulp-eslint": "^3.0.0", 22 | "gulp-filter": "^4.0.0", 23 | "gulp-htmlmin": "^2.0.0", 24 | "gulp-if": "^2.0.0", 25 | "gulp-imagemin": "^3.0.1", 26 | "gulp-inject": "^4.0.0", 27 | "gulp-jsonlint": "^1.1.0", 28 | "gulp-load-plugins": "^1.0.0-rc", 29 | "gulp-natural-sort": "^0.1.0", 30 | "gulp-ng-annotate": "^2.0.0", 31 | "gulp-plumber": "^1.0.1", 32 | "gulp-protractor": "^2.1.0", 33 | "gulp-rename": "^1.2.2", 34 | "gulp-sass": "^2.0.2", 35 | "gulp-shell": "^0.5.1", 36 | "gulp-size": "^2.0.0", 37 | "gulp-sourcemaps": "^1.5.2", 38 | "gulp-uglify": "^1.3.0", 39 | "gulp-useref": "^3.0.4", 40 | "karma": "^1.1.0", 41 | "karma-angular-filesort": "^1.0.0", 42 | "karma-jasmine": "^1.0.2", 43 | "karma-ng-html2js-preprocessor": "^1.0.0", 44 | "karma-phantomjs-launcher": "^1.0.0", 45 | "lodash": "^4.3.0", 46 | "main-bower-files": "^2.9.0", 47 | "minimist": "^1.2.0", 48 | "phantomjs-prebuilt": "^2.1.4", 49 | "plist": "^1.1.0", 50 | "proxy-middleware": "^0.15.0", 51 | "require-dir": "^0.3.0", 52 | "vinyl-paths": "^2.0.0", 53 | "wiredep": "^4.0.0", 54 | "xml2js": "^0.4.9", 55 | "yeoman-test": "^1.1.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /mobile-app/gulp/testing.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // gulp 3 | var gulp = require('gulp'); 4 | var path = require('path'); 5 | var paths = gulp.paths; 6 | var options = gulp.options; 7 | // plugins 8 | var $ = require('gulp-load-plugins')(); 9 | // modules 10 | var Server = require('karma').Server; 11 | var bs = require('browser-sync'); 12 | 13 | // KARMA 14 | function runKarma (singleRun, done) { 15 | new Server({ 16 | configFile: path.join(__dirname, '/../karma.conf.js'), 17 | singleRun: singleRun, 18 | autoWatch: !singleRun 19 | }, done).start(); 20 | } 21 | 22 | gulp.task('karma', ['linting'], function (done) { 23 | runKarma(true, done); 24 | }); 25 | 26 | gulp.task('karma:auto', ['linting'], function (done) { 27 | runKarma(false, done); 28 | }); 29 | 30 | // PROTRACTOR 31 | // Downloads the selenium webdriver 32 | gulp.task('webdriver-update', $.protractor.webdriver_update); 33 | gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); 34 | 35 | function runProtractor (done) { 36 | gulp.src(paths.protractor) 37 | .pipe($.protractor.protractor({ 38 | configFile: 'protractor.conf.js' 39 | })) 40 | .on('error', function (err) { 41 | // Make sure failed tests cause gulp to exit non-zero 42 | throw err; 43 | }) 44 | .on('end', function () { 45 | bs.get('m-ionic').exit(); 46 | done(); 47 | }); 48 | } 49 | 50 | gulp.task('protractor', ['serve', 'linting', 'webdriver-update'], function (done) { 51 | runProtractor(done); 52 | }); 53 | 54 | var protractorBuildDeps = ['serve-build', 'webdriver-update']; 55 | if (options.build !== false) { 56 | protractorBuildDeps.push('build'); 57 | } 58 | gulp.task('protractor-build', protractorBuildDeps, function (done) { 59 | gulp.start('linting'); 60 | 61 | runProtractor(done); 62 | }); 63 | -------------------------------------------------------------------------------- /mobile-app/gulp/utils/Patcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | var et = require('elementtree'); // also included in gen-m/package.json 6 | var chalk = require('chalk'); 7 | 8 | function Patcher (projectRoot) { 9 | this.projectRoot = projectRoot || '.'; 10 | } 11 | 12 | Patcher.prototype.parseXml = function (filename) { 13 | return new et.ElementTree(et.XML(fs.readFileSync(filename, 'utf-8'))); 14 | }; 15 | 16 | Patcher.prototype.patchConfigXml = function (externalUrl) { 17 | var platforms = ['android', 'ios']; 18 | platforms.forEach(function (platform) { 19 | 20 | var CONFIG_LOCATION = { 21 | android: 'res/xml', 22 | // retrieve project name which is necessary for ios config.xml path 23 | ios: this.getProjectName() 24 | }; 25 | 26 | // retrieve platform's path to config.xml & parse it 27 | var configXmlPath = path.join(this.projectRoot, 'platforms', platform, CONFIG_LOCATION[platform], 'config.xml'); 28 | var configXml = this.parseXml(configXmlPath); 29 | console.log(chalk.green('patching ') + configXmlPath); 30 | 31 | // set content src attrib to externalUrl 32 | var contentTag = configXml.find('content[@src]'); 33 | contentTag.attrib.src = externalUrl; 34 | 35 | // Add allow-navigation element so it's possible to navigate to externalUrl 36 | var allowNavTag = et.SubElement(configXml.find('.'), 'allow-navigation'); 37 | allowNavTag.set('href', '*'); 38 | 39 | fs.writeFileSync(configXmlPath, configXml.write({ 40 | indent: 4 41 | }), 'utf-8'); 42 | }, this); 43 | }; 44 | 45 | Patcher.prototype.getProjectName = function () { 46 | var parsedConfigXML = this.parseXml(path.join(this.projectRoot, 'config.xml')); 47 | var nameTag = parsedConfigXML.find('name'); 48 | return nameTag.text; 49 | }; 50 | 51 | 52 | module.exports = Patcher; 53 | -------------------------------------------------------------------------------- /mobile-app/jenkins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # VARS 4 | REPOSITORY_NAME='generator-m-ionic-demo' 5 | REPOSITORY_BASE='https://github.com/mwaylabs/' 6 | # TODO: set BUILD variable 7 | BUILD=0 8 | 9 | echo -e '\n####################### CLONING #######################\n' 10 | git clone ${REPOSITORY_BASE}${REPOSITORY_NAME} 11 | cd ${REPOSITORY_NAME} 12 | 13 | # install dependencies 14 | echo -e '\n####################### INSTALL DEPENDENCIES #######################\n' 15 | echo -e 'installing npm packages' 16 | npm prune 17 | npm install 18 | echo -e 'installing bower packages' 19 | bower prune 20 | bower install 21 | 22 | echo -e '\n####################### CONFIGURATION #######################\n' 23 | # retrieve version from config.xml 24 | VERSION="$(gulp config --silent --getWidgetAttr=version)" 25 | # append the build number and save in config.xml 26 | gulp config --setWidgetAttr="version=${VERSION}" 27 | # set the android-versionCode 28 | gulp config --setWidgetAttr="android-versionCode=${BUILD}" 29 | gulp config --setWidgetAttr="android-versionName=${VERSION}.${BUILD}" 30 | gulp config --silent --setWidgetAttr="ios-CFBundleVersion=${VERSION}.${BUILD}" 31 | 32 | echo -e '\n####################### GULP BUILD #######################\n' 33 | # run gulp build explicitly to make it more obvious what's happening 34 | # build: inject version and build number into app 35 | # build: with dev environment and minify 36 | gulp build --buildVars="version:${VERSION},build:${BUILD}" --env=dev --minify 37 | 38 | echo -e '\n####################### BUILDING IOS #######################\n' 39 | # --no-build here so we can use the one we just built 40 | # provide resources set1 41 | gulp --cordova 'prepare ios' --no-build --res=set1 42 | 43 | echo -e '\n######################## BUILDING ANDROID #######################\n' 44 | # --no-build here so we can use the one we just built 45 | # provide different resources set 46 | gulp --cordova 'build android --release' --no-build --res=set2 47 | 48 | echo -e '\n####################### DONE #######################\n' 49 | -------------------------------------------------------------------------------- /mobile-app/app/main/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('main', [ 3 | 'ionic', 4 | 'ionic-material', 5 | 'ngCordova', 6 | 'ui.router', 7 | 'ngWebSocket', 8 | 'LocalStorageModule', 9 | ]) 10 | .factory('WebSocket', function ($websocket) { 11 | // Open a WebSocket connection 12 | var ws = $websocket('ws://localhost:5000/ws'); 13 | 14 | var collection = []; 15 | 16 | ws.onMessage( function (message) { 17 | collection.push(JSON.parse(message.data)); 18 | }); 19 | 20 | var methods = { 21 | collection: collection, 22 | sendUser: function (_auth, _username, _pw) { 23 | ws.send(JSON.stringify({ auth: _auth, username: _username, password: _pw})); 24 | }, 25 | sendJson: function (data) { 26 | ws.send(JSON.stringify(data)); 27 | } 28 | }; 29 | 30 | return methods; 31 | }) 32 | .config(function ($stateProvider, $urlRouterProvider) { 33 | 34 | // ROUTING with ui.router 35 | $urlRouterProvider.otherwise('/main/login'); 36 | $stateProvider 37 | // this state is placed in the in the index.html 38 | .state('main', { 39 | url: '/main', 40 | abstract: true, 41 | templateUrl: 'main/templates/menu.html', 42 | controller: 'MenuCtrl as menu' 43 | }) 44 | .state('main.login', { 45 | url: '/login', 46 | views: { 47 | 'pageContent': { 48 | templateUrl: 'main/templates/login.html', 49 | controller: 'LoginCtrl' 50 | } 51 | } 52 | }) 53 | .state('main.google-auth', { 54 | url: '/google-auth', 55 | views: { 56 | 'pageContent': { 57 | templateUrl: 'main/templates/google-auth.html', 58 | controller: 'GoogleAuthCtrl' 59 | } 60 | } 61 | }) 62 | .state('main.ptc-auth', { 63 | url: '/ptc-auth', 64 | views: { 65 | 'pageContent': { 66 | templateUrl: 'main/templates/ptc-auth.html', 67 | controller: 'PtcAuthCtrl' 68 | } 69 | } 70 | }) 71 | .state('main.map', { 72 | url: '/map', 73 | views: { 74 | 'pageContent': { 75 | templateUrl: 'main/templates/map.html', 76 | controller: 'MapCtrl' 77 | } 78 | } 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /mobile-app/gulp/building.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // gulp 3 | var gulp = require('gulp'); 4 | var options = gulp.options; 5 | var paths = gulp.paths; 6 | // plugins 7 | var $ = require('gulp-load-plugins')(); 8 | // modules 9 | var del = require('del'); 10 | var vinylPaths = require('vinyl-paths'); 11 | 12 | var buildDependencies = [ 13 | options['force-build'] ? 'linting' : 'linting-throw', 14 | 'build-app', 15 | 'build-templates', 16 | 'build-assets' 17 | ]; 18 | 19 | gulp.task('build', buildDependencies, function () { 20 | return gulp.src(paths.dist + '/**/*') 21 | .pipe($.size({showFiles: true})); 22 | }); 23 | 24 | gulp.task('clean', function () { 25 | // pattern is windows-friendly according to https://github.com/mwaylabs/generator-m-ionic/issues/223#issuecomment-196060284 26 | return gulp.src(['.tmp/**/*.*', paths.dist + '/**/*.*']) 27 | .pipe(vinylPaths(del)); 28 | }); 29 | 30 | // concatenate files in build:blocks inside index.html 31 | // and copy to build folder destinations 32 | gulp.task('build-app', ['clean', 'inject-all'], function () { 33 | var jsFilter = $.filter('**/*.js', {restore: true}); 34 | var cssFilter = $.filter('**/*.css', {restore: true}); 35 | 36 | var stream = gulp.src('app/index.html') // main html file 37 | .pipe($.useref({searchPath: '{.tmp,app}'})); // all assets (without index.html) 38 | 39 | if (options.minify) { 40 | stream 41 | .pipe(jsFilter) 42 | .pipe($.ngAnnotate({ 43 | add: true, 44 | sourcemap: true 45 | })) 46 | .pipe($.uglify()) 47 | .pipe(jsFilter.restore) 48 | .pipe(cssFilter) 49 | .pipe($.csso()) 50 | .pipe(cssFilter.restore); 51 | } 52 | 53 | stream.pipe(gulp.dest(paths.dist)); 54 | 55 | return stream; 56 | }); 57 | 58 | // copy templates 59 | gulp.task('build-templates', ['clean'], function () { 60 | return gulp.src(paths.templates) 61 | .pipe($.if(options.minify, $.htmlmin({ 62 | removeComments: true, 63 | removeCommentsFromCDATA: true, 64 | collapseWhitespace: true, 65 | conservativeCollapse: true, 66 | collapseInlineTagWhitespace: true 67 | }))) 68 | .pipe(gulp.dest(paths.dist)); 69 | }); 70 | 71 | // copy assets, wait for fonts 72 | gulp.task('build-assets', ['clean', 'bower-fonts'], function () { 73 | return gulp.src('app/*/assets/**/*') 74 | .pipe($.if(options.minify, $.imagemin())) 75 | .pipe(gulp.dest(paths.dist)); 76 | }); 77 | -------------------------------------------------------------------------------- /mobile-app/app/main/directives/show-when.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Source: https://github.com/andrewmcgivery/ionic-ion-showWhen 3 | angular.module('main') 4 | .directive('showWhen', ['$window', function($window) { 5 | return { 6 | restrict: 'A', 7 | link: function($scope, $element, $attr) { 8 | 9 | function checkExpose() { 10 | var mq = $attr.showWhen == 'large' ? '(min-width:768px)' : $attr.showWhen; 11 | if($window.matchMedia(mq).matches){ 12 | $element.removeClass('ng-hide'); 13 | } else { 14 | $element.addClass('ng-hide'); 15 | } 16 | } 17 | 18 | function onResize() { 19 | debouncedCheck(); 20 | } 21 | 22 | var debouncedCheck = ionic.debounce(function() { 23 | $scope.$apply(function(){ 24 | checkExpose(); 25 | }); 26 | }, 300, false); 27 | 28 | checkExpose(); 29 | 30 | ionic.on('resize', onResize, $window); 31 | 32 | $scope.$on('$destroy', function(){ 33 | ionic.off('resize', onResize, $window); 34 | }); 35 | 36 | } 37 | }; 38 | }]) 39 | 40 | .directive('hideWhen', ['$window', function($window) { 41 | return { 42 | restrict: 'A', 43 | link: function($scope, $element, $attr) { 44 | 45 | function checkExpose() { 46 | var mq = $attr.hideWhen == 'large' ? '(min-width:768px)' : $attr.hideWhen; 47 | if($window.matchMedia(mq).matches){ 48 | $element.addClass('ng-hide'); 49 | } else { 50 | $element.removeClass('ng-hide'); 51 | } 52 | } 53 | 54 | function onResize() { 55 | debouncedCheck(); 56 | } 57 | 58 | var debouncedCheck = ionic.debounce(function() { 59 | $scope.$apply(function(){ 60 | checkExpose(); 61 | }); 62 | }, 300, false); 63 | 64 | checkExpose(); 65 | 66 | ionic.on('resize', onResize, $window); 67 | 68 | $scope.$on('$destroy', function(){ 69 | ionic.off('resize', onResize, $window); 70 | }); 71 | 72 | } 73 | }; 74 | }]) 75 | 76 | .directive('showWhenState', ['$window','$state','$rootScope', function($window,$state,$rootScope) { 77 | return { 78 | restrict: 'A', 79 | link: function($scope, $element, $attr) { 80 | 81 | function checkExpose(){ 82 | var state = $state.current.name; 83 | var statesToMatch = $attr.showWhenState.split(" || "); 84 | 85 | if(statesToMatch.indexOf(state) > -1){ 86 | $element.removeClass('ng-hide'); 87 | } else { 88 | $element.addClass('ng-hide'); 89 | } 90 | } 91 | 92 | $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ 93 | checkExpose(); 94 | }) 95 | 96 | checkExpose(); 97 | } 98 | }; 99 | }]); -------------------------------------------------------------------------------- /mobile-app/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Wed Jul 01 2015 13:51:22 GMT+0200 (CEST) 3 | 4 | 'use strict'; 5 | 6 | module.exports = function (config) { 7 | // retrieve main files from bower 8 | var wiredep = require('wiredep'); 9 | var bowerFiles = wiredep({devDependencies: true}).js; 10 | 11 | config.set({ 12 | 13 | // base path that will be used to resolve all patterns (eg. files, exclude) 14 | basePath: '', 15 | 16 | // frameworks to use 17 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 18 | frameworks: ['jasmine', 'angular-filesort'], 19 | 20 | // sort app/**/*.js files 21 | angularFilesort: { 22 | whitelist: [ 23 | 'app/!(bower_components)/**/*.js' 24 | ] 25 | }, 26 | 27 | // list of files / patterns to load in the browser 28 | files: bowerFiles.concat([ 29 | // other 30 | 'app/!(bower_components)/**/*.js', 31 | // test 32 | 'test/karma/**/*.js', 33 | // templates 34 | 'app/**/templates/*.html' 35 | ]), 36 | 37 | // list of files to exclude 38 | exclude: [], 39 | 40 | // preprocess matching files before serving them to the browser 41 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 42 | preprocessors: { 43 | 'app/**/templates/*.html': ['ng-html2js'] 44 | }, 45 | 46 | // use template cache to avoid unexpected $http requests from ui-router 47 | // https://github.com/angular-ui/ui-router/issues/212#issuecomment-69974072 48 | ngHtml2JsPreprocessor: { 49 | moduleName: 'ngHtml2Js', 50 | stripPrefix: 'app/' // the path must be relative to the app.js 51 | }, 52 | 53 | // test results reporter to use 54 | // possible values: 'dots', 'progress' 55 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 56 | reporters: ['progress'], 57 | 58 | // web server port 59 | port: 9876, 60 | 61 | // enable / disable colors in the output (reporters and logs) 62 | colors: true, 63 | 64 | // level of logging 65 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 66 | logLevel: config.LOG_INFO, 67 | 68 | // enable / disable watching file and executing tests whenever any file changes 69 | autoWatch: true, 70 | 71 | // start these browsers 72 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 73 | browsers: ['PhantomJS'], 74 | 75 | // Continuous Integration mode 76 | // if true, Karma captures browsers, runs the tests and exits 77 | singleRun: false 78 | }); 79 | }; 80 | -------------------------------------------------------------------------------- /mobile-app/gulp/watching.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // gulp 3 | var gulp = require('gulp'); 4 | var paths = gulp.paths; 5 | var options = gulp.options; 6 | // modules 7 | var bs = require('browser-sync').create('m-ionic'); 8 | var chalk = require('chalk'); 9 | 10 | var bsInit = function (paths, openOverride) { 11 | var bsOptions = { 12 | server: { 13 | baseDir: paths 14 | } 15 | }; 16 | if (options.proxyMapTo && options.proxyPath) { 17 | var url = require('url'); 18 | var proxy = require('proxy-middleware'); 19 | var proxyOptions = url.parse(options.proxyMapTo); 20 | proxyOptions.route = options.proxyPath; 21 | 22 | bsOptions.server.middleware = [proxy(proxyOptions)]; 23 | 24 | console.log('[' + chalk.green('proxy') + '] ' + chalk.bold('Proxy Configuration:')); 25 | console.log(chalk.dim(' ---------------------------------------')); 26 | console.log(' Path: ' + chalk.green(options.proxyPath)); 27 | console.log(' Map to: ' + chalk.green(options.proxyMapTo)); 28 | console.log(chalk.dim(' ---------------------------------------')); 29 | } 30 | if (options.open === false) { 31 | bsOptions.open = false; 32 | } 33 | if (openOverride !== undefined) { 34 | bsOptions.open = openOverride; 35 | } 36 | bs.init(bsOptions); 37 | }; 38 | 39 | // WATCH 40 | gulp.task('watch', ['inject-all'], function () { 41 | 42 | // browser sync server 43 | bsInit(['app', '.tmp']); 44 | 45 | // start linting and watching 46 | gulp.start('linting'); 47 | gulp.watch(paths.watchFiles, function (event) { 48 | console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); 49 | if (event.type === 'changed') { 50 | bs.reload(); 51 | gulp.start('linting'); 52 | } 53 | else { // added or deleted 54 | // inject in index (implicitly reloads) 55 | gulp.start('inject-all'); 56 | } 57 | }); 58 | // watch for changes in scss 59 | gulp.watch(paths.scssFiles, ['styles']); 60 | // watch for changes in css 61 | gulp.watch(paths.cssFiles, function () { 62 | bs.reload(); 63 | }); 64 | // watch for changes in environment files and new config files 65 | gulp.watch([ 66 | 'app/main/constants/env-*.json', 67 | 'app/*/constants/*config-const.js' 68 | ], ['environment']); 69 | }); 70 | 71 | // WATCH-BUILD 72 | var watchBuildDeps = []; 73 | if (options.build !== false) { 74 | watchBuildDeps.push('build'); 75 | } 76 | gulp.task('watch-build', watchBuildDeps, function () { 77 | bsInit(paths.dist); 78 | gulp.watch(paths.dist + '/**/*', function () { 79 | bs.reload(); 80 | }); 81 | }); 82 | 83 | // SERVE TASKS FOR PROTRACTOR 84 | gulp.task('serve', ['inject-all'], function () { 85 | bsInit(['app', '.tmp'], false); 86 | }); 87 | gulp.task('serve-build', ['build'], function () { 88 | bsInit(['app', '.tmp'], false); 89 | }); 90 | -------------------------------------------------------------------------------- /mobile-app/gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var gulp = require('gulp'); 3 | var minimist = require('minimist'); 4 | var requireDir = require('require-dir'); 5 | var chalk = require('chalk'); 6 | var fs = require('fs'); 7 | 8 | // config 9 | var paths = gulp.paths = { 10 | bowerComponents: 'app/bower_components', 11 | dist: 'www', 12 | jsFiles: ['app/**/*.js', '!app/bower_components/**/*.js'], 13 | jsonFiles: ['app/**/*.json', '!app/bower_components/**/*.json'], 14 | scssFiles: ['app/*/styles/**/*.scss'], 15 | cssFiles: ['.tmp/*/styles/*.css'], 16 | templates: ['app/*/templates/**/*'], 17 | contrib: ['gulpfile.js', 'gulp/**/*.js', 'hooks/**/*.js'], 18 | karma: ['test/karma/**/*.js'], 19 | protractor: ['test/protractor/**/*.js'] 20 | }; 21 | paths.watchFiles = paths.jsFiles 22 | .concat([ 23 | 'app/index.html', 24 | 'app/*/assets/**/*' 25 | ]) 26 | .concat(paths.templates); 27 | 28 | // OPTIONS 29 | var options = gulp.options = minimist(process.argv.slice(2)); 30 | 31 | // load .gulp_settings.json 32 | var task = options._[0]; // only for first task 33 | var gulpSettings; 34 | if (fs.existsSync('./gulp/.gulp_settings.json')) { 35 | gulpSettings = require('./gulp/.gulp_settings.json'); 36 | var defaults = gulpSettings.defaults; 37 | if (defaults) { 38 | // defaults present for said task? 39 | if (task && task.length && defaults[task]) { 40 | var taskDefaults = defaults[task]; 41 | // copy defaults to options object 42 | for (var key in taskDefaults) { 43 | // only if they haven't been explicitly set 44 | if (options[key] === undefined) { 45 | options[key] = taskDefaults[key]; 46 | } 47 | } 48 | } 49 | } 50 | } 51 | 52 | // environment 53 | options.env = options.env || 'dev'; 54 | // print options 55 | if (defaults && defaults[task]) { 56 | console.log(chalk.green('defaults for task \'' + task + '\': '), defaults[task]); 57 | } 58 | // cordova command one of cordova's build commands? 59 | if (options.cordova) { 60 | var cmds = ['build', 'run', 'emulate', 'prepare', 'serve']; 61 | for (var i = 0, cmd; ((cmd = cmds[i])); i++) { 62 | if (options.cordova.indexOf(cmd) >= 0) { 63 | options.cordovaBuild = true; 64 | break; 65 | } 66 | } 67 | } 68 | 69 | // load tasks 70 | requireDir('./gulp'); 71 | 72 | // default task 73 | gulp.task('default', function () { 74 | // cordova build command & gulp build 75 | if (options.cordovaBuild && options.build !== false) { 76 | return gulp.start('cordova-with-build'); 77 | } 78 | // cordova build command & no gulp build 79 | else if (options.cordovaBuild && options.build === false) { 80 | return gulp.start('cordova-only-resources'); 81 | } 82 | // cordova non-build command 83 | else if (options.cordova) { 84 | return gulp.start('cordova'); 85 | } 86 | // livereload command 87 | else if (options.livereload) { 88 | options.build = false; // build not necessary, take whatever's in www 89 | return gulp.start('livereload'); 90 | } 91 | // just watch when cordova option not present 92 | else { 93 | return gulp.start('watch'); 94 | } 95 | }); 96 | -------------------------------------------------------------------------------- /mobile-app/gulp/cordova.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // gulp 3 | var gulp = require('gulp'); 4 | var options = gulp.options; 5 | var paths = gulp.paths; 6 | // plugins 7 | var $ = require('gulp-load-plugins')(); 8 | // packages 9 | var path = require('path'); 10 | var process = require('process'); 11 | var del = require('del'); 12 | var vinylPaths = require('vinyl-paths'); 13 | var bs = require('browser-sync').create('m-ionic:livereload'); 14 | var Patcher = require('./utils/Patcher'); 15 | 16 | var runCordova = function (command, stream) { 17 | // allow to overwrite command from option.cordova with parameter 18 | command = typeof command === 'string' ? command : options.cordova; 19 | // create new stream if not provided 20 | stream = stream || gulp.src(''); 21 | return stream 22 | .pipe($.shell([ 23 | // needs explicit cross-platform path 24 | path.join('node_modules/cordova/bin/cordova ') + command 25 | ])); 26 | }; 27 | 28 | // CORDOVA 29 | gulp.task('cordova', runCordova); 30 | gulp.task('cordova-only-resources', ['resources'], runCordova); 31 | gulp.task('cordova-with-build', ['build', 'resources'], runCordova); 32 | 33 | // RESOURCES 34 | gulp.task('clean-res', function () { 35 | return gulp.src('res/*/current/*') 36 | .pipe(vinylPaths(del)); 37 | }); 38 | gulp.task('resources', ['clean-res'], function () { 39 | var setFolder = options.res || 'default'; 40 | 41 | var resourceFiles = 'res/*/' + setFolder + '/**/*'; 42 | return gulp.src(resourceFiles) 43 | .pipe($.rename(function (path) { 44 | path.dirname = path.dirname.replace('/' + setFolder, '/current'); 45 | })) 46 | .pipe(gulp.dest('res')); 47 | }); 48 | 49 | // LIVERELOAD 50 | gulp.task('livereload', ['serve-livereload'], function () { 51 | return runCordova(options.livereload + ' --noprepare'); 52 | }); 53 | gulp.task('serve-livereload', ['cordova-prepare'], function (done) { 54 | var bsOptions = { 55 | logConnections: true, 56 | open: false, 57 | files: ['app', '.tmp'], 58 | server: { 59 | baseDir: ['app', '.tmp', 'platforms/ios/www/', 'platforms/android/assets/www/'], 60 | // platform www's for cordova.js 61 | } 62 | }; 63 | 64 | bs.init(bsOptions, function (err, bsInstance) { 65 | if (err) { 66 | console.log(err); 67 | } 68 | var urls = bsInstance.options.getIn(['urls']); 69 | var patcher = new Patcher(process.cwd()); 70 | // patch platform's config xml to allow navigation to 71 | // & to set content tag to bs externalUrl 72 | patcher.patchConfigXml(urls.get('external')); 73 | done(); 74 | 75 | // start linting and watching 76 | gulp.start('linting'); 77 | gulp.watch(paths.watchFiles, function (event) { 78 | console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); 79 | if (event.type === 'changed') { 80 | gulp.start('linting'); 81 | } 82 | else { // added or deleted 83 | // inject in index (implicitly reloads) 84 | gulp.start('inject-all'); 85 | } 86 | }); 87 | // watch for changes in scss 88 | gulp.watch(paths.scssFiles, ['styles']); 89 | // watch for changes in environment files and new config files 90 | gulp.watch([ 91 | 'app/main/constants/env-*.json', 92 | 'app/*/constants/*config-const.js' 93 | ], ['environment']); 94 | 95 | }); 96 | }); 97 | gulp.task('cordova-prepare', ['inject-all'], function () { 98 | return runCordova('prepare'); 99 | }); 100 | -------------------------------------------------------------------------------- /mobile-app/gulp/configuring.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | // gulp 4 | var gulp = require('gulp'); 5 | var options = gulp.options; 6 | // other 7 | var chalk = require('chalk'); 8 | var minimist = require('minimist'); 9 | var fs = require('fs'); 10 | var xml2js = require('xml2js'); 11 | 12 | gulp.task('config', function () { 13 | var parser = new xml2js.Parser(); 14 | var builder = new xml2js.Builder({ 15 | renderOpts: { 16 | pretty: true, 17 | indent: ' ' 18 | }, 19 | xmldec: { 20 | version: '1.0', 21 | encoding: 'utf-8' 22 | } 23 | }); 24 | // read & parse file 25 | var xmlFile = fs.readFileSync('config.xml'); 26 | parser.parseString(xmlFile, function (err, result) { 27 | // get values 28 | if (options.getWidgetAttr) { 29 | console.log(result.widget.$[options.getWidgetAttr]); 30 | } 31 | // update values 32 | if (options.setWidgetAttr) { 33 | var split = options.setWidgetAttr.split('='); 34 | var key = split[0]; 35 | var value = split[1]; 36 | result.widget.$[key] = value; 37 | } 38 | 39 | if (options.setName) { 40 | result.widget.name = options.setName; 41 | } 42 | if (options.setDescription) { 43 | result.widget.description = options.setDescription; 44 | } 45 | if (options.setAuthor) { 46 | var splits = options.setAuthor.split('---'); 47 | if (splits[0]) { 48 | result.widget.author[0]._ = splits[0]; 49 | } 50 | if (splits[1]) { 51 | result.widget.author[0].$.email = splits[1]; 52 | } 53 | if (splits[2]) { 54 | result.widget.author[0].$.href = splits[2]; 55 | } 56 | } 57 | // write file 58 | var xml = builder.buildObject(result); 59 | fs.writeFileSync('config.xml', xml); 60 | }); 61 | }); 62 | 63 | gulp.task('defaults', function () { 64 | var filePath = './gulp/.gulp_settings.json'; 65 | var exists = fs.existsSync(filePath); 66 | 67 | var fileContent = {}; 68 | if (exists) { 69 | fileContent = JSON.parse(fs.readFileSync(filePath, 'utf-8')); 70 | } 71 | var defaults = fileContent.defaults; 72 | 73 | // set 74 | if (options.set) { 75 | if (typeof options.set !== 'string') { 76 | console.log(chalk.red('Use like this: --set=\' --flag1 --flag2=value\'')); 77 | return; 78 | } 79 | 80 | var newDefaults = minimist(options.set.split(' ')); 81 | if (!defaults) { 82 | fileContent.defaults = defaults = {}; 83 | } 84 | 85 | var setTask = newDefaults._[0]; 86 | delete newDefaults._; 87 | defaults[setTask] = newDefaults; 88 | 89 | console.log(chalk.green('set defaults for task \'' + setTask + '\': '), newDefaults); 90 | } 91 | // clear 92 | else if (options.clear) { 93 | var clearTask = options.clear; 94 | if (typeof clearTask !== 'string') { 95 | console.log(chalk.red('Use like this: --clear ')); 96 | return; 97 | } 98 | if (!defaults || !defaults[clearTask]) { 99 | console.log(chalk.yellow('Nothing to clear')); 100 | return; 101 | } 102 | 103 | delete defaults[clearTask]; 104 | console.log(chalk.yellow('cleared defaults for task \'' + clearTask + '\'')); 105 | 106 | // last? -> delete defaults object 107 | if (!Object.keys(defaults).length) { 108 | delete fileContent.defaults; 109 | } 110 | } 111 | // show 112 | else { 113 | if (defaults) { 114 | console.log(chalk.green('defaults:')); 115 | for (var key in defaults) { 116 | console.log(chalk.green(key + ': '), defaults[key]); 117 | } 118 | } 119 | else { 120 | console.log(chalk.yellow('no defaults yet')); 121 | } 122 | } 123 | 124 | // write changes to file 125 | if (options.clear || options.set) { 126 | fs.writeFileSync(filePath, JSON.stringify(fileContent, undefined, 2)); 127 | } 128 | }); 129 | -------------------------------------------------------------------------------- /mobile-app/gulp/injecting.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // gulp 3 | var gulp = require('gulp'); 4 | var paths = gulp.paths; 5 | var options = gulp.options; 6 | // plugins 7 | var $ = require('gulp-load-plugins')(); 8 | // modules 9 | var wiredep = require('wiredep'); 10 | var mainBowerFiles = require('main-bower-files'); 11 | 12 | // inject app/**/*.js, bower components, css into index.html 13 | // inject environment variables into config.js constant 14 | gulp.task('inject-all', ['styles', 'wiredep', 'bower-fonts', 'environment', 'build-vars'], function () { 15 | 16 | return gulp.src('app/index.html') 17 | .pipe( 18 | $.inject( // app/**/*.js files 19 | gulp.src(paths.jsFiles) 20 | .pipe($.plumber()) // use plumber so watch can start despite js errors 21 | .pipe($.naturalSort()) 22 | .pipe($.angularFilesort()), 23 | {relative: true})) 24 | .pipe( 25 | $.inject( // inject compiled css 26 | gulp.src(paths.cssFiles, {read: false}) 27 | .pipe($.naturalSort()), 28 | { 29 | ignorePath: '../.tmp', 30 | relative: true, 31 | })) 32 | .pipe(gulp.dest('app')); 33 | }); 34 | 35 | // build styles to tmp 36 | gulp.task('styles', ['clean'], function () { 37 | 38 | // compile css starting from each module's scss 39 | return gulp.src('app/*/styles/!(_)*.scss') 40 | .pipe($.plumber()) 41 | .pipe($.sourcemaps.init()) 42 | .pipe($.sass.sync().on('error', $.sass.logError)) 43 | .pipe($.sourcemaps.write()) 44 | .pipe($.autoprefixer({ browsers: ['last 2 versions'], remove: false})) 45 | .pipe(gulp.dest('.tmp/')); 46 | }); 47 | 48 | // inject bower components into index.html 49 | gulp.task('wiredep', function () { 50 | 51 | return gulp.src('app/index.html') 52 | // exclude ionic scss since we're using ionic sass 53 | .pipe(wiredep.stream({exclude: ['bower_components/ionic/release/css']})) 54 | .pipe(gulp.dest('app/')); 55 | }); 56 | 57 | // copy bower fonts 58 | gulp.task('bower-fonts', function () { 59 | // to app/main/assets/fonts (path can be set in app/main/styles/.scss) 60 | var DEST = 'app/main/assets/fonts'; 61 | var fontFiles = mainBowerFiles({filter: /\.(eot|otf|svg|ttf|woff|woff2)$/i}) 62 | .concat('app/main/assets/fonts/**/*'); 63 | 64 | return gulp.src(fontFiles) 65 | .pipe($.changed(DEST)) 66 | .pipe(gulp.dest(DEST)); 67 | }); 68 | 69 | /** 70 | * transforms object into a string format that is ready for injection at indentation 4 71 | * @param {Object} obj Object with values to inject 72 | * @return {String} properly formatted string 73 | */ 74 | var injectFormat = function (obj) { 75 | // indentation of 2 76 | obj = JSON.stringify(obj, null, 2); 77 | // replace all doublequotes with singlequotes 78 | obj = obj.replace(/\"/g, '\''); 79 | // remove first and last line curly braces 80 | obj = obj.replace(/^\{\n/, '').replace(/\n\}$/, ''); 81 | // remove indentation of first line 82 | obj = obj.replace(/^( ){2}/, ''); 83 | // insert padding for all remaining lines 84 | obj = obj.replace(/\n( ){2}/g, '\n '); 85 | 86 | return obj; 87 | }; 88 | 89 | gulp.task('environment', function () { 90 | return gulp.src('app/*/constants/*const.js') 91 | .pipe( 92 | $.inject( 93 | gulp.src('app/main/constants/env-' + options.env + '.json'), 94 | { 95 | starttag: '/*inject-env*/', 96 | endtag: '/*endinject*/', 97 | transform: function (filePath, file) { 98 | var json; 99 | try { 100 | json = JSON.parse(file.contents.toString('utf8')); 101 | } 102 | catch (e) { 103 | console.log(e); 104 | } 105 | 106 | if (json) { 107 | json = injectFormat(json); 108 | } 109 | return json; 110 | } 111 | })) 112 | .pipe(gulp.dest('app/')); 113 | }); 114 | 115 | gulp.task('build-vars', ['environment'], function () { 116 | return gulp.src('app/*/constants/*const.js') 117 | .pipe( 118 | $.inject( 119 | gulp.src(''), 120 | { 121 | starttag: '/*inject-build*/', 122 | endtag: '/*endinject*/', 123 | transform: function () { 124 | var obj = {}; 125 | var buildVars = options.buildVars; 126 | 127 | if (buildVars) { 128 | // loop over build variables 129 | var variables = buildVars.split(','); 130 | for (var i = 0, variable; ((variable = variables[i])); i++) { 131 | var splits = variable.split(':'); 132 | // add key and value to object 133 | obj[splits[0]] = splits[1]; 134 | } 135 | return injectFormat(obj); 136 | } 137 | else { 138 | return; 139 | } 140 | } 141 | })) 142 | .pipe(gulp.dest('app/')); 143 | }); 144 | -------------------------------------------------------------------------------- /mobile-app/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | PokemonGo-Bot 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /mobile-app/app/main/controllers/map-ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('main').controller('MapCtrl', function ($log, $scope, $ionicHistory) { 3 | 4 | // var path = $location.path(); 5 | // $scope.options = $scope.options || {}; 6 | // if (path.indexOf('submit') != -1) { 7 | // $scope.options.hideBackButton = true; 8 | // } else { 9 | // $scope.options.hideBackButton = false; 10 | // } 11 | 12 | $ionicHistory.nextViewOptions({ 13 | disableBack: true 14 | }); 15 | 16 | function addLocationMarker (latLng) { 17 | var marker = new google.maps.Marker({ 18 | position: latLng, 19 | map: $scope.map, 20 | animation: google.maps.Animation.DROP, 21 | }); 22 | google.maps.event.addListener(marker, 'click', function () { 23 | //infowindow.open(map, marker); 24 | $log.log('location marker clicked'); 25 | }); 26 | } 27 | 28 | 29 | // Source: https://jsfiddle.net/ogsvzacz/6/ 30 | function addLocationButton () 31 | { 32 | var controlDiv = document.createElement('div'); 33 | var firstChild = document.createElement('button'); 34 | firstChild.style.backgroundColor = '#fff'; 35 | firstChild.style.border = 'none'; 36 | firstChild.style.outline = 'none'; 37 | firstChild.style.width = '28px'; 38 | firstChild.style.height = '28px'; 39 | firstChild.style.borderRadius = '2px'; 40 | firstChild.style.boxShadow = '0 1px 4px rgba(0,0,0,0.3)'; 41 | firstChild.style.cursor = 'pointer'; 42 | firstChild.style.marginRight = '10px'; 43 | firstChild.style.padding = '0'; 44 | //firstChild.title = 'Your Location'; 45 | controlDiv.appendChild(firstChild); 46 | 47 | var secondChild = document.createElement('div'); 48 | secondChild.style.margin = '5px'; 49 | secondChild.style.width = '18px'; 50 | secondChild.style.height = '18px'; 51 | secondChild.style.backgroundImage = 'url(https://maps.gstatic.com/tactile/mylocation/mylocation-sprite-2x.png)'; 52 | secondChild.style.backgroundSize = '180px 18px'; 53 | secondChild.style.backgroundPosition = '0 0'; 54 | secondChild.style.backgroundRepeat = 'no-repeat'; 55 | firstChild.appendChild(secondChild); 56 | 57 | google.maps.event.addListener($scope.map, 'center_changed', function () { 58 | secondChild.style['background-position'] = '0 0'; 59 | }); 60 | 61 | firstChild.addEventListener('click', function () { 62 | var imgX = '0', 63 | animationInterval = setInterval( function () { 64 | imgX = imgX === '-18' ? '0' : '-18'; 65 | secondChild.style['background-position'] = imgX + 'px 0'; 66 | }, 500); 67 | 68 | if (navigator.geolocation) { 69 | navigator.geolocation.getCurrentPosition( function (position) { 70 | var latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); 71 | addLocationMarker(latLng); 72 | $scope.map.setCenter(latLng); 73 | clearInterval(animationInterval); 74 | secondChild.style['background-position'] = '-144px 0'; 75 | }); 76 | } else { 77 | clearInterval(animationInterval); 78 | secondChild.style['background-position'] = '0 0'; 79 | } 80 | }); 81 | 82 | controlDiv.index = 1; 83 | $scope.map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(controlDiv); 84 | } 85 | 86 | function initializeGoogleMap () { 87 | /* global google */ 88 | var defaultLocation = new google.maps.LatLng(40.7828647, -73.9675491); 89 | var mapOptions = { 90 | center: defaultLocation, 91 | zoom: 16, 92 | mapTypeId: google.maps.MapTypeId.ROADMAP, 93 | mapTypeControl: true, 94 | mapTypeControlOptions: { 95 | style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR, 96 | position: google.maps.ControlPosition.TOP_LEFT 97 | }, 98 | zoomControl: true, 99 | zoomControlOptions: { 100 | position: google.maps.ControlPosition.CENTER_RIGHT 101 | }, 102 | scaleControl: true, 103 | streetViewControl: false, 104 | fullscreenControl: false 105 | }; 106 | 107 | var map = new google.maps.Map(document.getElementById('map'), mapOptions); 108 | $scope.map = map; 109 | 110 | addLocationMarker(defaultLocation); 111 | // Create location button after $scope.map is set 112 | addLocationButton(); 113 | } 114 | 115 | $scope.initMap = initializeGoogleMap(); 116 | 117 | $scope.centerOnMe = function () { 118 | if (!$scope.map) { 119 | return; 120 | } 121 | $log.log('Loading detected location...'); 122 | // $scope.loading = $ionicLoading.show({ 123 | // content: 'Getting current location...', 124 | // showBackdrop: false 125 | // }); 126 | navigator.geolocation.getCurrentPosition(function (pos) { 127 | $scope.map.setCenter(new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude)); 128 | //$scope.loading.hide(); 129 | }, function (error) { 130 | $log.log('Unable to get location: ' + error.message); 131 | }); 132 | }; 133 | 134 | // $scope.clickTest = function () { 135 | // alert('Example of infowindow with ng-click'); 136 | // }; 137 | }); 138 | -------------------------------------------------------------------------------- /mobile-app/README.md: -------------------------------------------------------------------------------- 1 | # PokemonGo-Bot 2 | This project was generated with Generator-M-Ionic v1.9.2. For more info visit the [repository](https://github.com/mwaylabs/generator-m-ionic) or check out the README below. 3 | 4 | # Generator-M-Ionic v1.9.2 5 | 6 | [![NPM version](http://img.shields.io/npm/v/generator-m-ionic.svg?style=flat-square)][npm-url] 7 | [![Coverage Status](http://img.shields.io/coveralls/mwaylabs/generator-m-ionic/master.svg?style=flat-square)][coveralls-url] 8 | [![Build Status](https://img.shields.io/travis/mwaylabs/generator-m-ionic/master.svg?style=flat-square)][travis-url] 9 | [![Dependency Status](http://img.shields.io/david/mwaylabs/generator-m-ionic/master.svg?style=flat-square)][daviddm-url] 10 | [![Download Month](http://img.shields.io/npm/dm/generator-m-ionic.svg?style=flat-square)][npm-url] 11 | 12 | [npm-url]: https://npmjs.org/package/generator-m-ionic 13 | [coveralls-url]: https://coveralls.io/r/mwaylabs/generator-m-ionic?branch=master 14 | [travis-url]: https://travis-ci.org/mwaylabs/generator-m-ionic 15 | [daviddm-url]: https://david-dm.org/mwaylabs/generator-m-ionic 16 | 17 | Development: 18 | 19 | [![Dev Coverage Status](http://img.shields.io/coveralls/mwaylabs/generator-m-ionic/dev.svg?style=flat-square)][coveralls-url] 20 | [![Dev Build Status](https://img.shields.io/travis/mwaylabs/generator-m-ionic/dev.svg?style=flat-square)][travis-url] 21 | [![Dev Dependency Status](http://img.shields.io/david/mwaylabs/generator-m-ionic/dev.svg?style=flat-square)](https://david-dm.org/mwaylabs/generator-m-ionic/dev) 22 | 23 | 24 | ## Why you need it 25 |

26 | 27 | 28 | 29 |

30 | 31 | > **Advanced workflows for building rock-solid Ionic apps**: develop, prototype, test, build and deliver high quality apps with Yeoman, Gulp, Bower, Angular, Cordova and of course Ionic. All in one sexy generator. 32 | 33 | **[Read more ... ](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/intro/why_you_need_it.md)** 34 | 35 | ### What's in the box 36 |
37 |
38 |

39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 |
62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |

78 |
79 |
80 | 81 | **[Read more ...](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/intro/whats_in_the_box.md)** 82 | 83 | ### What's new 84 | 1.9.0 85 | - **Livereload** for the device! Wohoo! See [how it's done](https://github.com/mwaylabs/generator-m-ionic/blob/master/docs/guides/development_intro.md#run-on-device-or-emulator-with-livereload). 86 | - **Testing workflow** improvements 87 | - **Precommit hooks** and others in a new [Husky Guide](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/testing_workflow.md) 88 | - **gulp protractor** now returns, allowing it to be used with husky, travis, jenkins, ... 89 | - **Questions** the generator asks are documented and explained in the [Questions](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/questions.md) document 90 | - [read more ...](https://github.com/mwaylabs/generator-m-ionic/releases/tag/1.9.0) 91 | 92 | ## Quick Start 93 | - [Quick Start](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/intro/quick_start.md) for the experienced developer. 94 | - [Try the demo](https://github.com/mwaylabs/generator-m-ionic-demo). Get a quick impression by cloning the sample project generated with the latest version of Generator-M-Ionic. 95 | 96 | 97 | ## Guides 98 | ##### Setup 99 | - [Installation and Prerequisites](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/installation_prerequisites.md) 100 | - [Questions](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/questions.md) the generator will ask and what they mean 101 | 102 | ##### Basics 103 | - [Development Introduction](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/development_intro.md) 104 | - [File structure](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/file_structure.md) 105 | - [Sub-generators](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/sub_generators.md) for adding new components. 106 | - [Git integration](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/git_integration.md), see how it's done. 107 | - [Sass integration](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/sass_integration.md) in our module concept. 108 | - [Bower component usage](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/bower_component_usage.md) in our module concept. 109 | - [Ionic style source](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/ionic_style_source.md), change it from CSS to Sass or vice versa. 110 | 111 | ##### Quality 112 | - [ESLint](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/eslint.md) code style checks and setting up your IDE/Editor. 113 | - [Testing](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/testing.md) with our testing setup. 114 | - [Husky hooks](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/testing_workflow.md), automatically run linting and tests before you commit. 115 | 116 | ##### Advanced 117 | - [CORS & Proxying](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/cors_proxy.md), how to cope with CORS issues. 118 | - [App Icons and splash screens](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/icons_splash_screens.md), a simple setup or different sets for different builds - all is possible. 119 | - [Use Environments](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/environments.md) manage different API Endpoints and much more with just a single parameter. 120 | - [Gulp defaults](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/gulp_defaults.md), spare yourself some tedious typing on the command line. 121 | - [Generator Update (experimental)](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/generator_update.md) can help you update to a new generator version. 122 | 123 | 124 | ##### Building & Continuous Integration 125 | - [Build Vars](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/build_vars.md), inject vars into your app at build time. 126 | - [Programmatically change the `config.xml`](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/guides/programmatically_change_configxml.md), an essential part for a successful continuous integration setup. Add environments and build vars for a full blown continuous integration use case! 127 | 128 | ##### Ecosystems 129 | - [Ionic Platform](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/ecosystems/ionic_platform.md) (beta) - A cloud platform for managing and scaling cross-platform mobile apps 130 | - [Appmobi](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/ecosystems/appmobi.md) - Secure Mobile Development Platform 131 | - [ApiOmat](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/ecosystems/apiomat.md) (beta) - Enterprise Backend as a Service 132 | 133 | ## Generator Insights 134 | We've published 3 blog articles on our company blog delivering deep insights into the why and how of the generator: 135 | - September 2015: [Generator-M-Ionic and the search for the holy grail](http://blog.mwaysolutions.com/2015/09/21/generator-m-ionic-and-the-search-for-the-holy-grail/) 136 | - rather **technical comparison** between the generator and similar tools as well as technical insights to the **decisions and motivation** behind the generator 137 | - September 2015: [Generator-M-Ionic: HTML5 mobile app development evolved](http://blog.mwaysolutions.com/2015/09/10/generator-m-ionic-html5-mobile-app-development-evolved/) 138 | - provides insight to the **technology choices and ecosystem** and the **benefits of using the generator** 139 | - March 2015: [Generator-M: the state of HTML5 mobile app development at M-Way](http://blog.mwaysolutions.com/2015/03/26/generator-m-the-state-of-html5-mobile-app-development-at-m-way/) 140 | - the **origins** of the generator development and **company strategy** 141 | 142 | 143 | ## Questions, issues? Talk to us! 144 | Do the following: 145 | 1. check out our [Issue Guidelines](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/contribute/issue_guide.md) and [issues](https://github.com/mwaylabs/generator-m-ionic/issues) to see if there already is a solution or answer. 146 | 2. [![Join the chat at https://gitter.im/mwaylabs/generator-m-ionic](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mwaylabs/generator-m-ionic?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - Get in touch with other developers and our core team. 147 | 3. If all fails, make sure you have read the [Issue Guidelines](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/contribute/issue_guide.md) **first** and then [open a new issue](https://github.com/mwaylabs/generator-m-ionic/issues/new). 148 | 149 | ## Want to contribute ideas, code? 150 | Start by reading our: 151 | 152 | 1. [Mission Statement](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/contribute/mission_statement.md) 153 | 2. [Contribution Guide](https://github.com/mwaylabs/generator-m-ionic/tree/master/docs/contribute/contribution_guide.md) 154 | 155 | 156 | ## License 157 | Code licensed under MIT. Docs under Apache 2. PhoneGap is a trademark of Adobe. 158 | -------------------------------------------------------------------------------- /mobile-app/hooks/after_prepare/update_platform_config.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | // taken from https://github.com/diegonetto/generator-ionic/blob/master/templates/hooks/after_prepare/update_platform_config.js 5 | 6 | /** This hook updates platform configuration files based on preferences and config-file data defined in config.xml. 7 | Currently only the AndroidManifest.xml and IOS *-Info.plist file are supported. 8 | 9 | Preferences: 10 | 1. Preferences defined outside of the platform element will apply to all platforms 11 | 2. Preferences defined inside a platform element will apply only to the specified platform 12 | 3. Platform preferences take precedence over common preferences 13 | 4. The preferenceMappingData object contains all of the possible custom preferences to date including the 14 | target file they belong to, parent element, and destination element or attribute 15 | 16 | Config Files 17 | 1. config-file elements MUST be defined inside a platform element, otherwise they will be ignored. 18 | 2. config-file target attributes specify the target file to update. (AndroidManifest.xml or *-Info.plist) 19 | 3. config-file parent attributes specify the parent element (AndroidManifest.xml) or parent key (*-Info.plist) 20 | that the child data will replace or be appended to. 21 | 4. config-file elements are uniquely indexed by target AND parent for each platform. 22 | 5. If there are multiple config-file's defined with the same target AND parent, the last config-file will be used 23 | 6. Elements defined WITHIN a config-file will replace or be appended to the same elements relative to the parent element 24 | 7. If a unique config-file contains multiples of the same elements (other than uses-permssion elements which are 25 | selected by by the uses-permission name attribute), the last defined element will be retrieved. 26 | 27 | Examples: 28 | 29 | AndroidManifest.xml 30 | NOTE: For possible manifest values see http://developer.android.com/guide/topics/manifest/manifest-intro.html 31 | 32 | 33 | //These preferences are actually available in Cordova by default although not currently documented 34 | 35 | 36 | 37 | 38 | //custom preferences examples 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | *-Info.plist 59 | 60 | 61 | 62 | 63 | UIInterfaceOrientationLandscapeOmg 64 | 65 | 66 | 67 | 68 | someValue 69 | 70 | 71 | 72 | NOTE: Currently, items aren't removed from the platform config files if you remove them from config.xml. 73 | For example, if you add a custom permission, build the remove it, it will still be in the manifest. 74 | If you make a mistake, for example adding an element to the wrong parent, you may need to remove and add your platform, 75 | or revert to your previous manifest/plist file. 76 | 77 | TODO: We may need to capture all default manifest/plist elements/keys created by Cordova along with any plugin elements/keys to compare against custom elements to remove. 78 | */ 79 | 80 | // global vars 81 | var fs = require('fs'); 82 | var path = require('path'); 83 | var _ = require('lodash'); 84 | var et = require('elementtree'); 85 | var plist = require('plist'); 86 | 87 | var rootdir = path.resolve(__dirname, '../../'); 88 | 89 | var platformConfig = (function () { 90 | /* Global object that defines the available custom preferences for each platform. 91 | Maps a config.xml preference to a specific target file, parent element, and destination attribute or element 92 | */ 93 | var preferenceMappingData = { 94 | 'android': { 95 | 'android-manifest-hardwareAccelerated': { 96 | target: 'AndroidManifest.xml', 97 | parent: './', 98 | destination: 'android:hardwareAccelerated' 99 | }, 100 | 'android-installLocation': { 101 | target: 'AndroidManifest.xml', 102 | parent: './', 103 | destination: 'android:installLocation' 104 | }, 105 | 'android-activity-hardwareAccelerated': { 106 | target: 'AndroidManifest.xml', 107 | parent: 'application', 108 | destination: 'android:hardwareAccelerated' 109 | }, 110 | 'android-configChanges': { 111 | target: 'AndroidManifest.xml', 112 | parent: 'application/activity[@android:name=\'CordovaApp\']', 113 | destination: 'android:configChanges' 114 | }, 115 | 'android-launchMode': { 116 | target: 'AndroidManifest.xml', 117 | parent: 'application/activity[@android:name=\'CordovaApp\']', 118 | destination: 'android:launchMode' 119 | }, 120 | 'android-theme': { 121 | target: 'AndroidManifest.xml', 122 | parent: 'application/activity[@android:name=\'CordovaApp\']', 123 | destination: 'android:theme' 124 | }, 125 | 'android-windowSoftInputMode': { 126 | target: 'AndroidManifest.xml', 127 | parent: 'application/activity[@android:name=\'CordovaApp\']', 128 | destination: 'android:windowSoftInputMode' 129 | } 130 | }, 131 | 'ios': {} 132 | }; 133 | var configXmlData, preferencesData; 134 | 135 | return { 136 | // Parses a given file into an elementtree object 137 | parseElementtreeSync: function (filename) { 138 | var contents = fs.readFileSync(filename, 'utf-8'); 139 | if (contents) { 140 | //Windows is the BOM. Skip the Byte Order Mark. 141 | contents = contents.substring(contents.indexOf('<')); 142 | } 143 | return new et.ElementTree(et.XML(contents)); 144 | }, 145 | 146 | // Converts an elementtree object to an xml string. Since this is used for plist values, we don't care about attributes 147 | eltreeToXmlString: function (data) { 148 | var tag = data.tag; 149 | var el = '<' + tag + '>'; 150 | 151 | if (data.text && data.text.trim()) { 152 | el += data.text.trim(); 153 | } else { 154 | _.each(data.getchildren(), function (child) { 155 | el += platformConfig.eltreeToXmlString(child); 156 | }); 157 | } 158 | 159 | el += ''; 160 | return el; 161 | }, 162 | 163 | // Parses the config.xml into an elementtree object and stores in the config object 164 | getConfigXml: function () { 165 | if (!configXmlData) { 166 | configXmlData = this.parseElementtreeSync(path.join(rootdir, 'config.xml')); 167 | } 168 | 169 | return configXmlData; 170 | }, 171 | 172 | /* Retrieves all from config.xml and returns a map of preferences with platform as the key. 173 | If a platform is supplied, common prefs + platform prefs will be returned, otherwise just common prefs are returned. 174 | */ 175 | getPreferences: function (platform) { 176 | var configXml = this.getConfigXml(); 177 | 178 | //init common config.xml prefs if we haven't already 179 | if (!preferencesData) { 180 | preferencesData = { 181 | common: configXml.findall('preference') 182 | }; 183 | } 184 | 185 | var prefs = preferencesData.common || []; 186 | if (platform) { 187 | if (!preferencesData[platform]) { 188 | preferencesData[platform] = configXml.findall('platform[@name=\'' + platform + '\']/preference'); 189 | } 190 | prefs = prefs.concat(preferencesData[platform]); 191 | } 192 | 193 | return prefs; 194 | }, 195 | 196 | /* Retrieves all configured xml for a specific platform/target/parent element nested inside a platforms config-file 197 | element within the config.xml. The config-file elements are then indexed by target|parent so if there are 198 | any config-file elements per platform that have the same target and parent, the last config-file element is used. 199 | */ 200 | getConfigFilesByTargetAndParent: function (platform) { 201 | var configFileData = this.getConfigXml().findall('platform[@name=\'' + platform + '\']/config-file'); 202 | 203 | return _.keyBy(configFileData, function (item) { 204 | var parent = item.attrib.parent; 205 | //if parent attribute is undefined /* or */, set parent to top level elementree selector 206 | if (!parent || parent === '/*' || parent === '*/') { 207 | parent = './'; 208 | } 209 | return item.attrib.target + '|' + parent; 210 | }); 211 | }, 212 | 213 | // Parses the config.xml's preferences and config-file elements for a given platform 214 | parseConfigXml: function (platform) { 215 | var configData = {}; 216 | this.parsePreferences(configData, platform); 217 | this.parseConfigFiles(configData, platform); 218 | 219 | return configData; 220 | }, 221 | 222 | // Retrieves the config.xml's pereferences for a given platform and parses them into JSON data 223 | parsePreferences: function (configData, platform) { 224 | var preferences = this.getPreferences(platform), 225 | type = 'preference'; 226 | 227 | _.each(preferences, function (preference) { 228 | var prefMappingData = preferenceMappingData[platform][preference.attrib.name], 229 | target, 230 | prefData; 231 | 232 | if (prefMappingData) { 233 | prefData = { 234 | parent: prefMappingData.parent, 235 | type: type, 236 | destination: prefMappingData.destination, 237 | data: preference 238 | }; 239 | 240 | target = prefMappingData.target; 241 | if (!configData[target]) { 242 | configData[target] = []; 243 | } 244 | configData[target].push(prefData); 245 | } 246 | }); 247 | }, 248 | 249 | // Retrieves the config.xml's config-file elements for a given platform and parses them into JSON data 250 | parseConfigFiles: function (configData, platform) { 251 | var configFiles = this.getConfigFilesByTargetAndParent(platform), 252 | type = 'configFile'; 253 | 254 | _.each(configFiles, function (configFile, key) { 255 | var keyParts = key.split('|'); 256 | var target = keyParts[0]; 257 | var parent = keyParts[1]; 258 | var items = configData[target] || []; 259 | 260 | _.each(configFile.getchildren(), function (element) { 261 | items.push({ 262 | parent: parent, 263 | type: type, 264 | destination: element.tag, 265 | data: element 266 | }); 267 | }); 268 | 269 | configData[target] = items; 270 | }); 271 | }, 272 | 273 | // Parses config.xml data, and update each target file for a specified platform 274 | updatePlatformConfig: function (platform) { 275 | var configData = this.parseConfigXml(platform), 276 | platformPath = path.join(rootdir, 'platforms', platform); 277 | 278 | _.each(configData, function (configItems, targetFileName) { 279 | var projectName, targetFile; 280 | 281 | if (platform === 'ios' && targetFileName.indexOf('Info.plist') > -1) { 282 | projectName = platformConfig.getConfigXml().findtext('name'); 283 | targetFile = path.join(platformPath, projectName, projectName + '-Info.plist'); 284 | platformConfig.updateIosPlist(targetFile, configItems); 285 | } else if (platform === 'android' && targetFileName === 'AndroidManifest.xml') { 286 | targetFile = path.join(platformPath, targetFileName); 287 | platformConfig.updateAndroidManifest(targetFile, configItems); 288 | } 289 | }); 290 | }, 291 | 292 | // Updates the AndroidManifest.xml target file with data from config.xml 293 | updateAndroidManifest: function (targetFile, configItems) { 294 | var tempManifest = platformConfig.parseElementtreeSync(targetFile), 295 | root = tempManifest.getroot(); 296 | 297 | _.each(configItems, function (item) { 298 | // if parent is not found on the root, child/grandchild nodes are searched 299 | var parentEl = root.find(item.parent) || root.find('*/' + item.parent), 300 | data = item.data, 301 | childSelector = item.destination, 302 | childEl; 303 | 304 | if (!parentEl) { 305 | return; 306 | } 307 | 308 | if (item.type === 'preference') { 309 | parentEl.attrib[childSelector] = data.attrib.value; 310 | } else { 311 | // since there can be multiple uses-permission elements, we need to select them by unique name 312 | if (childSelector === 'uses-permission') { 313 | childSelector += '[@android:name=\'' + data.attrib['android:name'] + '\']'; 314 | } 315 | 316 | childEl = parentEl.find(childSelector); 317 | // if child element doesnt exist, create new element 318 | if (!childEl) { 319 | childEl = new et.Element(item.destination); 320 | parentEl.append(childEl); 321 | } 322 | 323 | // copy all config.xml data except for the generated _id property 324 | _.each(data, function (prop, propName) { 325 | if (propName !== '_id') { 326 | childEl[propName] = prop; 327 | } 328 | }); 329 | } 330 | }); 331 | 332 | fs.writeFileSync(targetFile, tempManifest.write({ 333 | indent: 4 334 | }), 'utf-8'); 335 | }, 336 | 337 | /* Updates the *-Info.plist file with data from config.xml by parsing to an xml string, then using the plist 338 | module to convert the data to a map. The config.xml data is then replaced or appended to the original plist file 339 | */ 340 | updateIosPlist: function (targetFile, configItems) { 341 | var infoPlist = plist.parse(fs.readFileSync(targetFile, 'utf-8')), 342 | tempInfoPlist; 343 | 344 | _.each(configItems, function (item) { 345 | var key = item.parent; 346 | var plistXml = '' + key + ''; 347 | plistXml += platformConfig.eltreeToXmlString(item.data) + ''; 348 | 349 | var configPlistObj = plist.parse(plistXml); 350 | infoPlist[key] = configPlistObj[key]; 351 | }); 352 | 353 | tempInfoPlist = plist.build(infoPlist); 354 | tempInfoPlist = tempInfoPlist.replace(/[\s\r\n]*<\/string>/g, ''); 355 | fs.writeFileSync(targetFile, tempInfoPlist, 'utf-8'); 356 | } 357 | }; 358 | })(); 359 | 360 | // Main 361 | (function () { 362 | if (rootdir) { 363 | // go through each of the platform directories that have been prepared 364 | var platforms = _.filter(fs.readdirSync('platforms'), function (file) { 365 | return fs.statSync(path.resolve('platforms', file)).isDirectory(); 366 | }); 367 | 368 | _.each(platforms, function (platform) { 369 | try { 370 | platform = platform.trim().toLowerCase(); 371 | platformConfig.updatePlatformConfig(platform); 372 | } catch (e) { 373 | process.stdout.write(e); 374 | } 375 | }); 376 | } 377 | })(); 378 | --------------------------------------------------------------------------------