├── .editorconfig
├── .eslintrc
├── .gitignore
├── LICENSE
├── README.md
├── config.xml
├── hooks
├── README.md
└── after_prepare
│ └── 010_add_platform_class.js
├── ionic.config.json
├── ionic.project
├── package.json
├── resources
├── 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-land-xhdpi-screen.png
│ │ ├── drawable-land-xxhdpi-screen.png
│ │ ├── drawable-land-xxxhdpi-screen.png
│ │ ├── drawable-port-hdpi-screen.png
│ │ ├── drawable-port-ldpi-screen.png
│ │ ├── drawable-port-mdpi-screen.png
│ │ ├── drawable-port-xhdpi-screen.png
│ │ ├── drawable-port-xxhdpi-screen.png
│ │ └── drawable-port-xxxhdpi-screen.png
├── icon-text.svg
├── icon.png
├── icon.svg
├── ios
│ ├── icon
│ │ ├── icon-40.png
│ │ ├── icon-40@2x.png
│ │ ├── icon-40@3x.png
│ │ ├── icon-50.png
│ │ ├── icon-50@2x.png
│ │ ├── icon-60.png
│ │ ├── icon-60@2x.png
│ │ ├── icon-60@3x.png
│ │ ├── icon-72.png
│ │ ├── icon-72@2x.png
│ │ ├── icon-76.png
│ │ ├── icon-76@2x.png
│ │ ├── icon-83.5@2x.png
│ │ ├── icon-small.png
│ │ ├── icon-small@2x.png
│ │ ├── icon-small@3x.png
│ │ ├── icon.png
│ │ └── icon@2x.png
│ └── splash
│ │ ├── Default-568h@2x~iphone.png
│ │ ├── Default-667h.png
│ │ ├── Default-736h.png
│ │ ├── Default-Landscape-736h.png
│ │ ├── Default-Landscape@2x~ipad.png
│ │ ├── Default-Landscape~ipad.png
│ │ ├── Default-Portrait@2x~ipad.png
│ │ ├── Default-Portrait~ipad.png
│ │ ├── Default@2x~iphone.png
│ │ └── Default~iphone.png
└── splash.png
├── shrinkwrap-check.js
├── src
├── CNAME
├── app
│ ├── app.component.ts
│ ├── app.html
│ ├── app.module.ts
│ ├── app.scss
│ └── main.ts
├── assets
│ ├── icon
│ │ └── favicon.ico
│ └── leaflet
│ │ ├── images
│ │ ├── layers-2x.png
│ │ ├── layers.png
│ │ ├── marker-icon-2x.png
│ │ ├── marker-icon.png
│ │ └── marker-shadow.png
│ │ └── leaflet.css
├── components
│ └── geofence-list-item
│ │ ├── geofence-list-item.html
│ │ └── geofence-list-item.ts
├── declarations.d.ts
├── index.html
├── manifest.json
├── models
│ └── geofence.ts
├── pages
│ ├── geofence-details
│ │ ├── geofence-details.html
│ │ ├── geofence-details.scss
│ │ └── geofence-details.ts
│ └── geofence-list
│ │ ├── geofence-list.html
│ │ ├── geofence-list.scss
│ │ └── geofence-list.ts
├── service-worker.js
├── services
│ ├── geofence-plugin-mock.ts
│ └── geofence-service.ts
├── theme
│ └── variables.scss
└── utils
│ └── uuid.ts
├── tsconfig.json
├── tslint.json
├── typings.json
└── typings
├── globals
└── cordova-plugin-geofence
│ ├── index.d.ts
│ └── typings.json
└── index.d.ts
/.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 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = true
12 | insert_final_newline = true
13 | indent_style = space
14 | indent_size = 2
15 |
16 | [*.js]
17 | indent_style = space
18 | indent_size = 2
19 |
20 | [*.ts]
21 | indent_style = space
22 | indent_size = 2
23 |
24 | [*.{css,scss}]
25 | indent_style = space
26 | indent_size = 2
27 |
28 | [*.html]
29 | indent_style = space
30 | indent_size = 2
31 |
32 | [*.{diff,md}]
33 | trim_trailing_whitespace = false
34 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb/base",
3 |
4 | "env": {
5 | "browser": true,
6 | "es6": true,
7 | "node": true
8 | },
9 |
10 | "rules": {
11 | "quotes": [2, "double", "avoid-escape"],
12 | "indent": [2, 2],
13 | "func-names": 0,
14 | "no-use-before-define": [2, "nofunc"],
15 | "prefer-arrow-callback": 0
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Specifies intentionally untracked files to ignore when using Git
2 | # http://git-scm.com/docs/gitignore
3 |
4 | *~
5 | *.sw[mnpcod]
6 | *.log
7 | *.tmp
8 | *.tmp.*
9 | log.txt
10 | *.sublime-project
11 | *.sublime-workspace
12 | .vscode/
13 | npm-debug.log*
14 |
15 | .idea/
16 | .sass-cache/
17 | .tmp/
18 | .versions/
19 | coverage/
20 | dist/
21 | node_modules/
22 | tmp/
23 | temp/
24 | hooks/
25 | platforms/
26 | plugins/
27 | plugins/android.json
28 | plugins/ios.json
29 | www/
30 | $RECYCLE.BIN/
31 |
32 | .DS_Store
33 | Thumbs.db
34 | UserInterfaceState.xcuserstate
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Tomasz Subik
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ionic2 geofence sample project
2 |
3 | Sample project using [cordova geofence plugin](https://github.com/cowbell/cordova-plugin-geofence) built with Ionic2 framework
4 |
5 | 
6 | 
7 |
8 | ## Working Example
9 |
10 | Check out [the working example](https://ionic2-geofence.surge.sh/) directly in your browser.
11 |
12 | ## Installation
13 |
14 | Use local npm packages
15 |
16 | ```
17 | npm install
18 | ```
19 |
20 | If you're using `ionic-cli` installed globally not locally you should install the latest beta version in order to run this project.
21 | ```
22 | npm install -g ionic@beta
23 | ```
24 |
25 | For testing in the browser
26 |
27 | ```
28 | ionic serve
29 | ```
30 |
31 | For android
32 |
33 | ```
34 | ionic platform add android
35 | ionic run android
36 | ```
37 |
38 | For iOS
39 |
40 | ```
41 | ionic platform add ios
42 | ionic run ios
43 | ```
44 |
45 | ## Platforms
46 |
47 | - Android
48 | - iOS
49 |
50 | ## License
51 |
52 | This software is released under the [MIT License](https://raw.githubusercontent.com/tsubik/ionic2-geofence/master/LICENSE).
53 |
54 | © 2016 Tomasz Subik. All rights reserved
55 |
--------------------------------------------------------------------------------
/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Ionic2 Geofence
4 | Sample Cordova Geofence Application Built With Ionic 2
5 | Tomasz Subik
6 |
7 |
8 |
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 |
34 |
35 |
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 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/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. Hook scripts could be defined by adding them to the special predefined folder (`/hooks`) or via configuration files (`config.xml` and `plugin.xml`) and run serially in the following order:
24 | * Application hooks from `/hooks`;
25 | * Application hooks from `config.xml`;
26 | * Plugin hooks from `plugins/.../plugin.xml`.
27 |
28 | __Remember__: Make your scripts executable.
29 |
30 | __Note__: `.cordova/hooks` directory is also supported for backward compatibility, but we don't recommend using it as it is deprecated.
31 |
32 | ## Supported hook types
33 | The following hook types are supported:
34 |
35 | after_build/
36 | after_compile/
37 | after_docs/
38 | after_emulate/
39 | after_platform_add/
40 | after_platform_rm/
41 | after_platform_ls/
42 | after_plugin_add/
43 | after_plugin_ls/
44 | after_plugin_rm/
45 | after_plugin_search/
46 | after_plugin_install/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed
47 | after_prepare/
48 | after_run/
49 | after_serve/
50 | before_build/
51 | before_compile/
52 | before_docs/
53 | before_emulate/
54 | before_platform_add/
55 | before_platform_rm/
56 | before_platform_ls/
57 | before_plugin_add/
58 | before_plugin_ls/
59 | before_plugin_rm/
60 | before_plugin_search/
61 | before_plugin_install/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed
62 | before_plugin_uninstall/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being uninstalled
63 | before_prepare/
64 | before_run/
65 | before_serve/
66 | pre_package/ <-- Windows 8 and Windows Phone only.
67 |
68 | ## Ways to define hooks
69 | ### Via '/hooks' directory
70 | To execute custom action when corresponding hook type is fired, use hook type as a name for a subfolder inside 'hooks' directory and place you script file here, for example:
71 |
72 | # script file will be automatically executed after each build
73 | hooks/after_build/after_build_custom_action.js
74 |
75 |
76 | ### Config.xml
77 |
78 | Hooks can be defined in project's `config.xml` using `` elements, for example:
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | ...
89 |
90 |
91 |
92 |
93 |
94 |
95 | ...
96 |
97 |
98 | ### Plugin hooks (plugin.xml)
99 |
100 | As a plugin developer you can define hook scripts using `` elements in a `plugin.xml` like that:
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | ...
109 |
110 |
111 | `before_plugin_install`, `after_plugin_install`, `before_plugin_uninstall` plugin hooks will be fired exclusively for the plugin being installed/uninstalled.
112 |
113 | ## Script Interface
114 |
115 | ### Javascript
116 |
117 | If you are writing hooks in Javascript you should use the following module definition:
118 | ```javascript
119 | module.exports = function(context) {
120 | ...
121 | }
122 | ```
123 |
124 | You can make your scipts async using Q:
125 | ```javascript
126 | module.exports = function(context) {
127 | var Q = context.requireCordovaModule('q');
128 | var deferral = new Q.defer();
129 |
130 | setTimeout(function(){
131 | console.log('hook.js>> end');
132 | deferral.resolve();
133 | }, 1000);
134 |
135 | return deferral.promise;
136 | }
137 | ```
138 |
139 | `context` object contains hook type, executed script full path, hook options, command-line arguments passed to Cordova and top-level "cordova" object:
140 | ```json
141 | {
142 | "hook": "before_plugin_install",
143 | "scriptLocation": "c:\\script\\full\\path\\appBeforePluginInstall.js",
144 | "cmdLine": "The\\exact\\command\\cordova\\run\\with arguments",
145 | "opts": {
146 | "projectRoot":"C:\\path\\to\\the\\project",
147 | "cordova": {
148 | "platforms": ["wp8"],
149 | "plugins": ["com.plugin.withhooks"],
150 | "version": "0.21.7-dev"
151 | },
152 | "plugin": {
153 | "id": "com.plugin.withhooks",
154 | "pluginInfo": {
155 | ...
156 | },
157 | "platform": "wp8",
158 | "dir": "C:\\path\\to\\the\\project\\plugins\\com.plugin.withhooks"
159 | }
160 | },
161 | "cordova": {...}
162 | }
163 |
164 | ```
165 | `context.opts.plugin` object will only be passed to plugin hooks scripts.
166 |
167 | You can also require additional Cordova modules in your script using `context.requireCordovaModule` in the following way:
168 | ```javascript
169 | var Q = context.requireCordovaModule('q');
170 | ```
171 |
172 | __Note__: new module loader script interface is used for the `.js` files defined via `config.xml` or `plugin.xml` only.
173 | For compatibility reasons hook files specified via `/hooks` folders are run via Node child_process spawn, see 'Non-javascript' section below.
174 |
175 | ### Non-javascript
176 |
177 | Non-javascript scripts are run via Node child_process spawn from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables:
178 |
179 | * CORDOVA_VERSION - The version of the Cordova-CLI.
180 | * CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios).
181 | * CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer)
182 | * CORDOVA_HOOK - Path to the hook that is being executed.
183 | * CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate)
184 |
185 | If a script returns a non-zero exit code, then the parent cordova command will be aborted.
186 |
187 | ## Writing hooks
188 |
189 | We highly recommend writing your hooks using Node.js so that they are
190 | cross-platform. Some good examples are shown here:
191 |
192 | [http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/)
193 |
194 | Also, note that even if you are working on Windows, and in case your hook scripts aren't bat files (which is recommended, if you want your scripts to work in non-Windows operating systems) Cordova CLI will expect a shebang line as the first line for it to know the interpreter it needs to use to launch the script. The shebang line should match the following example:
195 |
196 | #!/usr/bin/env [name_of_interpreter_executable]
197 |
--------------------------------------------------------------------------------
/hooks/after_prepare/010_add_platform_class.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | // Add Platform Class
4 | // v1.0
5 | // Automatically adds the platform class to the body tag
6 | // after the `prepare` command. By placing the platform CSS classes
7 | // directly in the HTML built for the platform, it speeds up
8 | // rendering the correct layout/style for the specific platform
9 | // instead of waiting for the JS to figure out the correct classes.
10 |
11 | var fs = require('fs');
12 | var path = require('path');
13 |
14 | var rootdir = process.argv[2];
15 |
16 | function addPlatformBodyTag(indexPath, platform) {
17 | // add the platform class to the body tag
18 | try {
19 | var platformClass = 'platform-' + platform;
20 | var cordovaClass = 'platform-cordova platform-webview';
21 |
22 | var html = fs.readFileSync(indexPath, 'utf8');
23 |
24 | var bodyTag = findBodyTag(html);
25 | if(!bodyTag) return; // no opening body tag, something's wrong
26 |
27 | if(bodyTag.indexOf(platformClass) > -1) return; // already added
28 |
29 | var newBodyTag = bodyTag;
30 |
31 | var classAttr = findClassAttr(bodyTag);
32 | if(classAttr) {
33 | // body tag has existing class attribute, add the classname
34 | var endingQuote = classAttr.substring(classAttr.length-1);
35 | var newClassAttr = classAttr.substring(0, classAttr.length-1);
36 | newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote;
37 | newBodyTag = bodyTag.replace(classAttr, newClassAttr);
38 |
39 | } else {
40 | // add class attribute to the body tag
41 | newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">');
42 | }
43 |
44 | html = html.replace(bodyTag, newBodyTag);
45 |
46 | fs.writeFileSync(indexPath, html, 'utf8');
47 |
48 | process.stdout.write('add to body class: ' + platformClass + '\n');
49 | } catch(e) {
50 | process.stdout.write(e);
51 | }
52 | }
53 |
54 | function findBodyTag(html) {
55 | // get the body tag
56 | try{
57 | return html.match(/])(.*?)>/gi)[0];
58 | }catch(e){}
59 | }
60 |
61 | function findClassAttr(bodyTag) {
62 | // get the body tag's class attribute
63 | try{
64 | return bodyTag.match(/ class=["|'](.*?)["|']/gi)[0];
65 | }catch(e){}
66 | }
67 |
68 | if (rootdir) {
69 |
70 | // go through each of the platform directories that have been prepared
71 | var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []);
72 |
73 | for(var x=0; x
2 |
3 |
4 |
122 |
--------------------------------------------------------------------------------
/resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/icon.png
--------------------------------------------------------------------------------
/resources/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
95 |
--------------------------------------------------------------------------------
/resources/ios/icon/icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-40.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-40@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-40@3x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-50.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-50@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-60.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-60@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-60@3x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-72.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-72@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-76.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-76@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-83.5@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-small.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-small@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon-small@3x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/icon/icon@2x.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-568h@2x~iphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default-568h@2x~iphone.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-667h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default-667h.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-736h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default-736h.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Landscape-736h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default-Landscape-736h.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Landscape@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default-Landscape@2x~ipad.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Landscape~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default-Landscape~ipad.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Portrait@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default-Portrait@2x~ipad.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Portrait~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default-Portrait~ipad.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default@2x~iphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default@2x~iphone.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default~iphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/ios/splash/Default~iphone.png
--------------------------------------------------------------------------------
/resources/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/resources/splash.png
--------------------------------------------------------------------------------
/shrinkwrap-check.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /* eslint-env node */
4 | /* eslint no-console: 0 */
5 |
6 | const fs = require('fs');
7 | const path = require('path');
8 | const _ = require('lodash');
9 | const shrinkwrapPath = 'npm-shrinkwrap.json';
10 |
11 | module.exports = function shrinkwrapCheck() {
12 | try {
13 | fs.accessSync(shrinkwrapPath);
14 | } catch (error) {
15 | console.error('npm-shrinkwrap.json file not found. Please run "npm shrinkwrap --dev" first.');
16 | process.exit(1);
17 | }
18 |
19 | const shrinkwrap = readFile(shrinkwrapPath);
20 | const dependencies = _(shrinkwrap.dependencies)
21 | .toPairs()
22 | .map((dependency) => (
23 | {
24 | name: dependency[0],
25 | version: dependency[1].version,
26 | }
27 | ));
28 |
29 | const hasPassed = dependencies
30 | .map(verifyDependency)
31 | .every((verification) => verification);
32 |
33 | if (!hasPassed) {
34 | console.error('\nSome installed dependencies are incorrect. Run "npm install" to fix it.');
35 | process.exit(1);
36 | }
37 |
38 | function readFile(filepath) {
39 | const file = fs.readFileSync(filepath);
40 | return JSON.parse(file);
41 | }
42 |
43 | function verifyDependency(dependency) {
44 | const packagePath = path.join('node_modules', dependency.name, 'package.json');
45 | const prefix = `${dependency.name}@${dependency.version}`;
46 |
47 | try {
48 | fs.accessSync(packagePath);
49 | } catch (error) {
50 | console.error(`${prefix}: missing.`);
51 | return false;
52 | }
53 |
54 | const installedVersion = readFile(packagePath).version;
55 | const requiredVersion = dependency.version;
56 |
57 | if (installedVersion !== requiredVersion) {
58 | console.error(`${prefix}: incorrect version installed ${installedVersion}.`);
59 | return false;
60 | }
61 |
62 | return true;
63 | }
64 | };
65 |
--------------------------------------------------------------------------------
/src/CNAME:
--------------------------------------------------------------------------------
1 | https://ionic2-geofence.surge.sh
2 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewChild } from "@angular/core";
2 | import { Nav, Platform, AlertController, MenuController } from "ionic-angular";
3 | import * as Leaflet from "leaflet";
4 |
5 | import { GeofenceListPage } from "../pages/geofence-list/geofence-list";
6 | import { GeofenceService } from "../services/geofence-service";
7 | import { GeofencePluginMock, TransitionType } from "../services/geofence-plugin-mock";
8 | import { FIXTURES } from "../models/geofence";
9 |
10 | @Component({
11 | templateUrl: "app.html"
12 | })
13 | export class MyApp {
14 | @ViewChild(Nav) nav: Nav;
15 |
16 | rootPage: any = GeofenceListPage;
17 |
18 | constructor(
19 | platform: Platform,
20 | private alertCtrl: AlertController,
21 | private geofenceService: GeofenceService,
22 | private menuCtrl: MenuController
23 | ) {
24 | platform.ready().then(() => {
25 | Leaflet.Icon.Default.imagePath = "assets/leaflet/images/";
26 |
27 | if (window.geofence === undefined) {
28 | console.warn("Geofence Plugin not found. Using mock instead.");
29 | window.geofence = GeofencePluginMock;
30 | window.TransitionType = TransitionType;
31 | }
32 |
33 | window.geofence.initialize().then((initStatus) => {
34 | console.log("Geofence Plugin has been initialized", initStatus);
35 | window.geofence.onTransitionReceived = function (geofences) {
36 | geofences.forEach(function (geo) {
37 | console.log("Geofence transition detected", geo);
38 | });
39 | };
40 |
41 | window.geofence.onNotificationClicked = function (notificationData) {
42 | console.log("App opened from Geo Notification!", notificationData);
43 | };
44 | }).catch((error) => {
45 | console.error(error);
46 | })
47 | });
48 | }
49 |
50 | addFixtures() {
51 | FIXTURES.forEach((fixture) => this.geofenceService.addOrUpdate(fixture));
52 | this.menuCtrl.close();
53 | }
54 |
55 | removeAll() {
56 | const confirm = this.alertCtrl.create({
57 | title: "Are you sure?",
58 | message: "Are you sure you want to remove all geofences?",
59 | buttons: [
60 | { text: "No" },
61 | {
62 | text: "Yes",
63 | handler: () => {
64 | this.geofenceService.removeAll();
65 | },
66 | },
67 | ],
68 | });
69 | this.menuCtrl.close();
70 | confirm.present();
71 | }
72 |
73 | testApp() {
74 | const confirm = this.alertCtrl.create({
75 | title: "Are you sure?",
76 | message: "Running tests will remove all your geofences. Do you want to continue?",
77 | buttons: [
78 | { text: "No" },
79 | {
80 | text: "Yes",
81 | handler: () => {
82 | window.location.href = "cdvtests/index.html";
83 | },
84 | },
85 | ],
86 | });
87 |
88 | this.menuCtrl.close();
89 | confirm.present();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/app/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
17 |
21 |
22 |
23 | Source
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ErrorHandler } from "@angular/core";
2 | import { IonicApp, IonicModule, IonicErrorHandler } from "ionic-angular";
3 |
4 | import { GeofenceDetailsPage } from "../pages/geofence-details/geofence-details";
5 | import { GeofenceListItem } from "../components/geofence-list-item/geofence-list-item";
6 | import { GeofenceListPage } from "../pages/geofence-list/geofence-list";
7 | import { GeofenceService } from "../services/geofence-service";
8 | import { MyApp } from "./app.component";
9 |
10 | const components = [
11 | MyApp,
12 | GeofenceDetailsPage,
13 | GeofenceListPage,
14 | GeofenceListItem
15 | ]
16 |
17 | @NgModule({
18 | declarations: components,
19 | imports: [
20 | IonicModule.forRoot(MyApp)
21 | ],
22 | bootstrap: [IonicApp],
23 | entryComponents: components,
24 | providers: [
25 | {provide: ErrorHandler, useClass: IonicErrorHandler},
26 | GeofenceService
27 | ]
28 | })
29 | export class AppModule {}
30 |
--------------------------------------------------------------------------------
/src/app/app.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/src/app/app.scss
--------------------------------------------------------------------------------
/src/app/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app.module';
4 |
5 | platformBrowserDynamic().bootstrapModule(AppModule);
6 |
--------------------------------------------------------------------------------
/src/assets/icon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/src/assets/icon/favicon.ico
--------------------------------------------------------------------------------
/src/assets/leaflet/images/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/src/assets/leaflet/images/layers-2x.png
--------------------------------------------------------------------------------
/src/assets/leaflet/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/src/assets/leaflet/images/layers.png
--------------------------------------------------------------------------------
/src/assets/leaflet/images/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/src/assets/leaflet/images/marker-icon-2x.png
--------------------------------------------------------------------------------
/src/assets/leaflet/images/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/src/assets/leaflet/images/marker-icon.png
--------------------------------------------------------------------------------
/src/assets/leaflet/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsubik/ionic2-geofence/30e4b17b73764896c5d880c0658f064f3b9c624c/src/assets/leaflet/images/marker-shadow.png
--------------------------------------------------------------------------------
/src/assets/leaflet/leaflet.css:
--------------------------------------------------------------------------------
1 | /* required styles */
2 |
3 | .leaflet-pane,
4 | .leaflet-tile,
5 | .leaflet-marker-icon,
6 | .leaflet-marker-shadow,
7 | .leaflet-tile-container,
8 | .leaflet-pane > svg,
9 | .leaflet-pane > canvas,
10 | .leaflet-zoom-box,
11 | .leaflet-image-layer,
12 | .leaflet-layer {
13 | position: absolute;
14 | left: 0;
15 | top: 0;
16 | }
17 | .leaflet-container {
18 | overflow: hidden;
19 | }
20 | .leaflet-tile,
21 | .leaflet-marker-icon,
22 | .leaflet-marker-shadow {
23 | -webkit-user-select: none;
24 | -moz-user-select: none;
25 | user-select: none;
26 | -webkit-user-drag: none;
27 | }
28 | /* Safari renders non-retina tile on retina better with this, but Chrome is worse */
29 | .leaflet-safari .leaflet-tile {
30 | image-rendering: -webkit-optimize-contrast;
31 | }
32 | /* hack that prevents hw layers "stretching" when loading new tiles */
33 | .leaflet-safari .leaflet-tile-container {
34 | width: 1600px;
35 | height: 1600px;
36 | -webkit-transform-origin: 0 0;
37 | }
38 | .leaflet-marker-icon,
39 | .leaflet-marker-shadow {
40 | display: block;
41 | }
42 | /* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
43 | /* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
44 | .leaflet-container .leaflet-overlay-pane svg,
45 | .leaflet-container .leaflet-marker-pane img,
46 | .leaflet-container .leaflet-shadow-pane img,
47 | .leaflet-container .leaflet-tile-pane img,
48 | .leaflet-container img.leaflet-image-layer {
49 | max-width: none !important;
50 | }
51 |
52 | .leaflet-container.leaflet-touch-zoom {
53 | -ms-touch-action: pan-x pan-y;
54 | touch-action: pan-x pan-y;
55 | }
56 | .leaflet-container.leaflet-touch-drag {
57 | -ms-touch-action: pinch-zoom;
58 | }
59 | .leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
60 | -ms-touch-action: none;
61 | touch-action: none;
62 | }
63 | .leaflet-tile {
64 | filter: inherit;
65 | visibility: hidden;
66 | }
67 | .leaflet-tile-loaded {
68 | visibility: inherit;
69 | }
70 | .leaflet-zoom-box {
71 | width: 0;
72 | height: 0;
73 | -moz-box-sizing: border-box;
74 | box-sizing: border-box;
75 | z-index: 800;
76 | }
77 | /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
78 | .leaflet-overlay-pane svg {
79 | -moz-user-select: none;
80 | }
81 |
82 | .leaflet-pane { z-index: 400; }
83 |
84 | .leaflet-tile-pane { z-index: 200; }
85 | .leaflet-overlay-pane { z-index: 400; }
86 | .leaflet-shadow-pane { z-index: 500; }
87 | .leaflet-marker-pane { z-index: 600; }
88 | .leaflet-tooltip-pane { z-index: 650; }
89 | .leaflet-popup-pane { z-index: 700; }
90 |
91 | .leaflet-map-pane canvas { z-index: 100; }
92 | .leaflet-map-pane svg { z-index: 200; }
93 |
94 | .leaflet-vml-shape {
95 | width: 1px;
96 | height: 1px;
97 | }
98 | .lvml {
99 | behavior: url(#default#VML);
100 | display: inline-block;
101 | position: absolute;
102 | }
103 |
104 |
105 | /* control positioning */
106 |
107 | .leaflet-control {
108 | position: relative;
109 | z-index: 800;
110 | pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
111 | pointer-events: auto;
112 | }
113 | .leaflet-top,
114 | .leaflet-bottom {
115 | position: absolute;
116 | z-index: 1000;
117 | pointer-events: none;
118 | }
119 | .leaflet-top {
120 | top: 0;
121 | }
122 | .leaflet-right {
123 | right: 0;
124 | }
125 | .leaflet-bottom {
126 | bottom: 0;
127 | }
128 | .leaflet-left {
129 | left: 0;
130 | }
131 | .leaflet-control {
132 | float: left;
133 | clear: both;
134 | }
135 | .leaflet-right .leaflet-control {
136 | float: right;
137 | }
138 | .leaflet-top .leaflet-control {
139 | margin-top: 10px;
140 | }
141 | .leaflet-bottom .leaflet-control {
142 | margin-bottom: 10px;
143 | }
144 | .leaflet-left .leaflet-control {
145 | margin-left: 10px;
146 | }
147 | .leaflet-right .leaflet-control {
148 | margin-right: 10px;
149 | }
150 |
151 |
152 | /* zoom and fade animations */
153 |
154 | .leaflet-fade-anim .leaflet-tile {
155 | will-change: opacity;
156 | }
157 | .leaflet-fade-anim .leaflet-popup {
158 | opacity: 0;
159 | -webkit-transition: opacity 0.2s linear;
160 | -moz-transition: opacity 0.2s linear;
161 | -o-transition: opacity 0.2s linear;
162 | transition: opacity 0.2s linear;
163 | }
164 | .leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
165 | opacity: 1;
166 | }
167 | .leaflet-zoom-animated {
168 | -webkit-transform-origin: 0 0;
169 | -ms-transform-origin: 0 0;
170 | transform-origin: 0 0;
171 | }
172 | .leaflet-zoom-anim .leaflet-zoom-animated {
173 | will-change: transform;
174 | }
175 | .leaflet-zoom-anim .leaflet-zoom-animated {
176 | -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
177 | -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
178 | -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
179 | transition: transform 0.25s cubic-bezier(0,0,0.25,1);
180 | }
181 | .leaflet-zoom-anim .leaflet-tile,
182 | .leaflet-pan-anim .leaflet-tile {
183 | -webkit-transition: none;
184 | -moz-transition: none;
185 | -o-transition: none;
186 | transition: none;
187 | }
188 |
189 | .leaflet-zoom-anim .leaflet-zoom-hide {
190 | visibility: hidden;
191 | }
192 |
193 |
194 | /* cursors */
195 |
196 | .leaflet-interactive {
197 | cursor: pointer;
198 | }
199 | .leaflet-grab {
200 | cursor: -webkit-grab;
201 | cursor: -moz-grab;
202 | }
203 | .leaflet-crosshair,
204 | .leaflet-crosshair .leaflet-interactive {
205 | cursor: crosshair;
206 | }
207 | .leaflet-popup-pane,
208 | .leaflet-control {
209 | cursor: auto;
210 | }
211 | .leaflet-dragging .leaflet-grab,
212 | .leaflet-dragging .leaflet-grab .leaflet-interactive,
213 | .leaflet-dragging .leaflet-marker-draggable {
214 | cursor: move;
215 | cursor: -webkit-grabbing;
216 | cursor: -moz-grabbing;
217 | }
218 |
219 | /* marker & overlays interactivity */
220 | .leaflet-marker-icon,
221 | .leaflet-marker-shadow,
222 | .leaflet-image-layer,
223 | .leaflet-pane > svg path,
224 | .leaflet-tile-container {
225 | pointer-events: none;
226 | }
227 |
228 | .leaflet-marker-icon.leaflet-interactive,
229 | .leaflet-image-layer.leaflet-interactive,
230 | .leaflet-pane > svg path.leaflet-interactive {
231 | pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
232 | pointer-events: auto;
233 | }
234 |
235 | /* visual tweaks */
236 |
237 | .leaflet-container {
238 | background: #ddd;
239 | outline: 0;
240 | }
241 | .leaflet-container a {
242 | color: #0078A8;
243 | }
244 | .leaflet-container a.leaflet-active {
245 | outline: 2px solid orange;
246 | }
247 | .leaflet-zoom-box {
248 | border: 2px dotted #38f;
249 | background: rgba(255,255,255,0.5);
250 | }
251 |
252 |
253 | /* general typography */
254 | .leaflet-container {
255 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
256 | }
257 |
258 |
259 | /* general toolbar styles */
260 |
261 | .leaflet-bar {
262 | box-shadow: 0 1px 5px rgba(0,0,0,0.65);
263 | border-radius: 4px;
264 | }
265 | .leaflet-bar a,
266 | .leaflet-bar a:hover {
267 | background-color: #fff;
268 | border-bottom: 1px solid #ccc;
269 | width: 26px;
270 | height: 26px;
271 | line-height: 26px;
272 | display: block;
273 | text-align: center;
274 | text-decoration: none;
275 | color: black;
276 | }
277 | .leaflet-bar a,
278 | .leaflet-control-layers-toggle {
279 | background-position: 50% 50%;
280 | background-repeat: no-repeat;
281 | display: block;
282 | }
283 | .leaflet-bar a:hover {
284 | background-color: #f4f4f4;
285 | }
286 | .leaflet-bar a:first-child {
287 | border-top-left-radius: 4px;
288 | border-top-right-radius: 4px;
289 | }
290 | .leaflet-bar a:last-child {
291 | border-bottom-left-radius: 4px;
292 | border-bottom-right-radius: 4px;
293 | border-bottom: none;
294 | }
295 | .leaflet-bar a.leaflet-disabled {
296 | cursor: default;
297 | background-color: #f4f4f4;
298 | color: #bbb;
299 | }
300 |
301 | .leaflet-touch .leaflet-bar a {
302 | width: 30px;
303 | height: 30px;
304 | line-height: 30px;
305 | }
306 |
307 |
308 | /* zoom control */
309 |
310 | .leaflet-control-zoom-in,
311 | .leaflet-control-zoom-out {
312 | font: bold 18px 'Lucida Console', Monaco, monospace;
313 | text-indent: 1px;
314 | }
315 | .leaflet-control-zoom-out {
316 | font-size: 20px;
317 | }
318 |
319 | .leaflet-touch .leaflet-control-zoom-in {
320 | font-size: 22px;
321 | }
322 | .leaflet-touch .leaflet-control-zoom-out {
323 | font-size: 24px;
324 | }
325 |
326 |
327 | /* layers control */
328 |
329 | .leaflet-control-layers {
330 | box-shadow: 0 1px 5px rgba(0,0,0,0.4);
331 | background: #fff;
332 | border-radius: 5px;
333 | }
334 | .leaflet-control-layers-toggle {
335 | background-image: url(images/layers.png);
336 | width: 36px;
337 | height: 36px;
338 | }
339 | .leaflet-retina .leaflet-control-layers-toggle {
340 | background-image: url(images/layers-2x.png);
341 | background-size: 26px 26px;
342 | }
343 | .leaflet-touch .leaflet-control-layers-toggle {
344 | width: 44px;
345 | height: 44px;
346 | }
347 | .leaflet-control-layers .leaflet-control-layers-list,
348 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle {
349 | display: none;
350 | }
351 | .leaflet-control-layers-expanded .leaflet-control-layers-list {
352 | display: block;
353 | position: relative;
354 | }
355 | .leaflet-control-layers-expanded {
356 | padding: 6px 10px 6px 6px;
357 | color: #333;
358 | background: #fff;
359 | }
360 | .leaflet-control-layers-scrollbar {
361 | overflow-y: scroll;
362 | padding-right: 5px;
363 | }
364 | .leaflet-control-layers-selector {
365 | margin-top: 2px;
366 | position: relative;
367 | top: 1px;
368 | }
369 | .leaflet-control-layers label {
370 | display: block;
371 | }
372 | .leaflet-control-layers-separator {
373 | height: 0;
374 | border-top: 1px solid #ddd;
375 | margin: 5px -10px 5px -6px;
376 | }
377 |
378 | /* Default icon URLs */
379 | .leaflet-default-icon-path {
380 | background-image: url(images/marker-icon.png);
381 | }
382 |
383 |
384 | /* attribution and scale controls */
385 |
386 | .leaflet-container .leaflet-control-attribution {
387 | background: #fff;
388 | background: rgba(255, 255, 255, 0.7);
389 | margin: 0;
390 | }
391 | .leaflet-control-attribution,
392 | .leaflet-control-scale-line {
393 | padding: 0 5px;
394 | color: #333;
395 | }
396 | .leaflet-control-attribution a {
397 | text-decoration: none;
398 | }
399 | .leaflet-control-attribution a:hover {
400 | text-decoration: underline;
401 | }
402 | .leaflet-container .leaflet-control-attribution,
403 | .leaflet-container .leaflet-control-scale {
404 | font-size: 11px;
405 | }
406 | .leaflet-left .leaflet-control-scale {
407 | margin-left: 5px;
408 | }
409 | .leaflet-bottom .leaflet-control-scale {
410 | margin-bottom: 5px;
411 | }
412 | .leaflet-control-scale-line {
413 | border: 2px solid #777;
414 | border-top: none;
415 | line-height: 1.1;
416 | padding: 2px 5px 1px;
417 | font-size: 11px;
418 | white-space: nowrap;
419 | overflow: hidden;
420 | -moz-box-sizing: border-box;
421 | box-sizing: border-box;
422 |
423 | background: #fff;
424 | background: rgba(255, 255, 255, 0.5);
425 | }
426 | .leaflet-control-scale-line:not(:first-child) {
427 | border-top: 2px solid #777;
428 | border-bottom: none;
429 | margin-top: -2px;
430 | }
431 | .leaflet-control-scale-line:not(:first-child):not(:last-child) {
432 | border-bottom: 2px solid #777;
433 | }
434 |
435 | .leaflet-touch .leaflet-control-attribution,
436 | .leaflet-touch .leaflet-control-layers,
437 | .leaflet-touch .leaflet-bar {
438 | box-shadow: none;
439 | }
440 | .leaflet-touch .leaflet-control-layers,
441 | .leaflet-touch .leaflet-bar {
442 | border: 2px solid rgba(0,0,0,0.2);
443 | background-clip: padding-box;
444 | }
445 |
446 |
447 | /* popup */
448 |
449 | .leaflet-popup {
450 | position: absolute;
451 | text-align: center;
452 | margin-bottom: 20px;
453 | }
454 | .leaflet-popup-content-wrapper {
455 | padding: 1px;
456 | text-align: left;
457 | border-radius: 12px;
458 | }
459 | .leaflet-popup-content {
460 | margin: 13px 19px;
461 | line-height: 1.4;
462 | }
463 | .leaflet-popup-content p {
464 | margin: 18px 0;
465 | }
466 | .leaflet-popup-tip-container {
467 | width: 40px;
468 | height: 20px;
469 | position: absolute;
470 | left: 50%;
471 | margin-left: -20px;
472 | overflow: hidden;
473 | pointer-events: none;
474 | }
475 | .leaflet-popup-tip {
476 | width: 17px;
477 | height: 17px;
478 | padding: 1px;
479 |
480 | margin: -10px auto 0;
481 |
482 | -webkit-transform: rotate(45deg);
483 | -moz-transform: rotate(45deg);
484 | -ms-transform: rotate(45deg);
485 | -o-transform: rotate(45deg);
486 | transform: rotate(45deg);
487 | }
488 | .leaflet-popup-content-wrapper,
489 | .leaflet-popup-tip {
490 | background: white;
491 | color: #333;
492 | box-shadow: 0 3px 14px rgba(0,0,0,0.4);
493 | }
494 | .leaflet-container a.leaflet-popup-close-button {
495 | position: absolute;
496 | top: 0;
497 | right: 0;
498 | padding: 4px 4px 0 0;
499 | border: none;
500 | text-align: center;
501 | width: 18px;
502 | height: 14px;
503 | font: 16px/14px Tahoma, Verdana, sans-serif;
504 | color: #c3c3c3;
505 | text-decoration: none;
506 | font-weight: bold;
507 | background: transparent;
508 | }
509 | .leaflet-container a.leaflet-popup-close-button:hover {
510 | color: #999;
511 | }
512 | .leaflet-popup-scrolled {
513 | overflow: auto;
514 | border-bottom: 1px solid #ddd;
515 | border-top: 1px solid #ddd;
516 | }
517 |
518 | .leaflet-oldie .leaflet-popup-content-wrapper {
519 | zoom: 1;
520 | }
521 | .leaflet-oldie .leaflet-popup-tip {
522 | width: 24px;
523 | margin: 0 auto;
524 |
525 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
526 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
527 | }
528 | .leaflet-oldie .leaflet-popup-tip-container {
529 | margin-top: -1px;
530 | }
531 |
532 | .leaflet-oldie .leaflet-control-zoom,
533 | .leaflet-oldie .leaflet-control-layers,
534 | .leaflet-oldie .leaflet-popup-content-wrapper,
535 | .leaflet-oldie .leaflet-popup-tip {
536 | border: 1px solid #999;
537 | }
538 |
539 |
540 | /* div icon */
541 |
542 | .leaflet-div-icon {
543 | background: #fff;
544 | border: 1px solid #666;
545 | }
546 |
547 |
548 | /* Tooltip */
549 | /* Base styles for the element that has a tooltip */
550 | .leaflet-tooltip {
551 | position: absolute;
552 | padding: 6px;
553 | background-color: #fff;
554 | border: 1px solid #fff;
555 | border-radius: 3px;
556 | color: #222;
557 | white-space: nowrap;
558 | -webkit-user-select: none;
559 | -moz-user-select: none;
560 | -ms-user-select: none;
561 | user-select: none;
562 | pointer-events: none;
563 | box-shadow: 0 1px 3px rgba(0,0,0,0.4);
564 | }
565 | .leaflet-tooltip.leaflet-clickable {
566 | cursor: pointer;
567 | pointer-events: auto;
568 | }
569 | .leaflet-tooltip-top:before,
570 | .leaflet-tooltip-bottom:before,
571 | .leaflet-tooltip-left:before,
572 | .leaflet-tooltip-right:before {
573 | position: absolute;
574 | pointer-events: none;
575 | border: 6px solid transparent;
576 | background: transparent;
577 | content: "";
578 | }
579 |
580 | /* Directions */
581 |
582 | .leaflet-tooltip-bottom {
583 | margin-top: 6px;
584 | }
585 | .leaflet-tooltip-top {
586 | margin-top: -6px;
587 | }
588 | .leaflet-tooltip-bottom:before,
589 | .leaflet-tooltip-top:before {
590 | left: 50%;
591 | margin-left: -6px;
592 | }
593 | .leaflet-tooltip-top:before {
594 | bottom: 0;
595 | margin-bottom: -12px;
596 | border-top-color: #fff;
597 | }
598 | .leaflet-tooltip-bottom:before {
599 | top: 0;
600 | margin-top: -12px;
601 | margin-left: -6px;
602 | border-bottom-color: #fff;
603 | }
604 | .leaflet-tooltip-left {
605 | margin-left: -6px;
606 | }
607 | .leaflet-tooltip-right {
608 | margin-left: 6px;
609 | }
610 | .leaflet-tooltip-left:before,
611 | .leaflet-tooltip-right:before {
612 | top: 50%;
613 | margin-top: -6px;
614 | }
615 | .leaflet-tooltip-left:before {
616 | right: 0;
617 | margin-right: -12px;
618 | border-left-color: #fff;
619 | }
620 | .leaflet-tooltip-right:before {
621 | left: 0;
622 | margin-left: -12px;
623 | border-right-color: #fff;
624 | }
625 |
--------------------------------------------------------------------------------
/src/components/geofence-list-item/geofence-list-item.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{header}}
4 | {{details}}
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/components/geofence-list-item/geofence-list-item.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, EventEmitter } from "@angular/core";
2 | import { GeofenceService } from "../../services/geofence-service";
3 |
4 | /*
5 | Generated class for the GeofenceListItem component.
6 |
7 | See https://angular.io/docs/ts/latest/api/core/ComponentMetadata-class.html
8 | for more info on Angular 2 Components.
9 | */
10 | @Component({
11 | selector: "geofence-list-item",
12 | templateUrl: "geofence-list-item.html"
13 | })
14 | export class GeofenceListItem {
15 | @Input() geofence: Geofence;
16 | @Output() onItemTapped: EventEmitter = new EventEmitter();
17 |
18 | constructor(private geofenceService: GeofenceService) {
19 |
20 | }
21 |
22 | get header() {
23 | return this.geofence.notification.text;
24 | }
25 |
26 | get details() {
27 | return `When ${this.transitionTypeText} within ${this.geofence.radius}m`;
28 | }
29 |
30 | get transitionTypeText() {
31 | switch(this.geofence.transitionType) {
32 | case 1: return "entering region";
33 | case 2: return "exiting region";
34 | case 3: return "entering or exiting region";
35 | }
36 | }
37 |
38 | itemTapped() {
39 | this.onItemTapped.emit(null);
40 | }
41 |
42 | remove() {
43 | this.geofenceService.remove(this.geofence);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/declarations.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Declaration files are how the Typescript compiler knows about the type information(or shape) of an object.
3 | They're what make intellisense work and make Typescript know all about your code.
4 |
5 | A wildcard module is declared below to allow third party libraries to be used in an app even if they don't
6 | provide their own type declarations.
7 |
8 | To learn more about using third party libraries in an Ionic app, check out the docs here:
9 | http://ionicframework.com/docs/v2/resources/third-party-libs/
10 |
11 | For more info on type definition files, check out the Typescript docs here:
12 | https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html
13 | */
14 | declare module '*';
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Ionic
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Ionic Geofence 2",
3 | "short_name": "Ionic Geofence 2",
4 | "start_url": "index.html",
5 | "display": "standalone",
6 | "icons": [{
7 | "src": "assets/imgs/logo.png",
8 | "sizes": "512x512",
9 | "type": "image/png"
10 | }],
11 | "background_color": "#4e8ef7",
12 | "theme_color": "#4e8ef7"
13 | }
14 |
--------------------------------------------------------------------------------
/src/models/geofence.ts:
--------------------------------------------------------------------------------
1 | export const FIXTURES = [
2 | { id: "1", latitude: 50.3021079, longitude: 18.6771861, radius: 3000, transitionType: 1, notification: { text: "Gliwice Train Station"} },
3 | { id: "2", latitude: 50.4728049, longitude: 19.0736874, radius: 3000, transitionType: 1, notification: { text: "Pyrzowice Airport"} },
4 | { id: "3", latitude: 50.0671974, longitude: 19.945232, radius: 3000, transitionType: 1, notification: { text: "Cracow Main Station"} },
5 | { id: "4", latitude: 52.2287803, longitude: 21.001124, radius: 3000, transitionType: 1, notification: { text: "Warsaw Main Station"} },
6 | { id: "5", latitude: 40.7257093, longitude: -74.0032786, radius: 4000, transitionType: 3, notification: { text: "New York - SOHO"} },
7 | { id: "6", latitude: 34.0033907, longitude: -118.5069657, radius: 3000, transitionType: 2, notification: { text: "LA - Santa Monica State Beach"} },
8 | { id: "7", latitude: 25.8938595, longitude: -80.1330216, radius: 500, transitionType: 1, notification: { text: "Dexter's Apartment - Miami Bay Harbour" } },
9 | ];
10 |
--------------------------------------------------------------------------------
/src/pages/geofence-details/geofence-details.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Edit Geofence
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | When you?
19 |
20 | Enter Region
21 | Exit Region
22 | Enter or Exit Region
23 |
24 |
25 |
26 |
27 | on
28 | {{radius}}m
29 |
30 |
31 |
32 |
36 |
37 |
--------------------------------------------------------------------------------
/src/pages/geofence-details/geofence-details.scss:
--------------------------------------------------------------------------------
1 | .geofence-details-page {
2 | .geofence-input-list {
3 | margin-bottom: 15px;
4 | }
5 |
6 | .geofence-radius-container {
7 | display: flex;
8 | justify-content: space-between;
9 | padding: 5px;
10 |
11 | .geofence-radius-input-container {
12 | width: 100%;
13 | padding-left: 10px;
14 | padding-right: 10px;
15 |
16 | input {
17 | width: 100%;
18 | }
19 | }
20 | }
21 |
22 | .map-container {
23 | width: 100%;
24 | position: absolute;
25 | top: 150px;
26 | bottom: 0px;
27 | }
28 |
29 | #map {
30 | width: 100%;
31 | height: 100%;
32 | }
33 |
34 | .scroll-content {
35 | overflow: hidden;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/pages/geofence-details/geofence-details.ts:
--------------------------------------------------------------------------------
1 | import { Component } from "@angular/core";
2 | import { NavController, NavParams, MenuController } from "ionic-angular";
3 | import * as Leaflet from "leaflet";
4 | import { GeofenceService } from "../../services/geofence-service";
5 |
6 | @Component({
7 | templateUrl: "geofence-details.html"
8 | })
9 | export class GeofenceDetailsPage {
10 | private geofence: Geofence;
11 | private _radius: number;
12 | private _latLng: any;
13 | private notificationText: string;
14 | private transitionType: string;
15 | private circle: any;
16 | private marker: any;
17 | private map: any;
18 |
19 | constructor(
20 | private nav: NavController,
21 | navParams: NavParams,
22 | private geofenceService: GeofenceService,
23 | private menu: MenuController
24 | ) {
25 | this.geofenceService = geofenceService;
26 | this.geofence = navParams.get("geofence");
27 | this.transitionType = this.geofence.transitionType.toString();
28 | this.notificationText = this.geofence.notification.text;
29 | this._radius = this.geofence.radius;
30 | this._latLng = Leaflet.latLng(this.geofence.latitude, this.geofence.longitude);
31 | }
32 |
33 | get radius() {
34 | return this._radius;
35 | }
36 |
37 | set radius(value) {
38 | this._radius = value;
39 | this.circle.setRadius(value);
40 | }
41 |
42 | set latLng(value) {
43 | this._latLng = value;
44 | this.circle.setLatLng(value);
45 | this.marker.setLatLng(value);
46 | }
47 |
48 | get latLng() {
49 | return this._latLng;
50 | }
51 |
52 | ionViewDidLoad() {
53 | this.menu.enable(false);
54 | // workaround map is not correctly displayed
55 | // maybe this should be done in some other event
56 | setTimeout(this.loadMap.bind(this), 100);
57 | }
58 |
59 | loadMap() {
60 | this.map = Leaflet
61 | .map("map")
62 | .setView(this.latLng, 13)
63 | .on("click", this.onMapClicked.bind(this))
64 |
65 | Leaflet.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png")
66 | .addTo(this.map);
67 |
68 | this.marker = Leaflet
69 | .marker(this.latLng, { draggable: true })
70 | .on("dragend", this.onMarkerPositionChanged.bind(this))
71 | .addTo(this.map);
72 |
73 | this.circle = Leaflet.circle(this.latLng, this.radius).addTo(this.map);
74 | }
75 |
76 | onMapClicked(e) {
77 | this.latLng = e.latlng;
78 | }
79 |
80 | onMarkerPositionChanged(e) {
81 | const latlng = e.target.getLatLng();
82 |
83 | this.latLng = latlng;
84 | }
85 |
86 | saveChanges() {
87 | const geofence = this.geofence;
88 |
89 | geofence.notification.text = this.notificationText;
90 | geofence.radius = this.radius;
91 | geofence.latitude = this.latLng.lat;
92 | geofence.longitude = this.latLng.lng;
93 | geofence.transitionType = parseInt(this.transitionType, 10);
94 |
95 | this.geofenceService.addOrUpdate(geofence).then(() => {
96 | this.nav.pop();
97 | });
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/pages/geofence-list/geofence-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 | Ionic2 Geofence Example
7 |
8 |
9 |
10 |
11 | 0">
12 |
13 |
14 |
15 |
16 |
17 |
18 | There are no geofences yet.
19 |
20 |
21 |
22 |
23 | Loading geofences...
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
--------------------------------------------------------------------------------
/src/pages/geofence-list/geofence-list.scss:
--------------------------------------------------------------------------------
1 | .geofence-list-page {
2 | ion-list {
3 | margin-bottom: 80px; /*space for fab button*/
4 | }
5 | }
6 |
7 | .add-geofence-button {
8 | z-index: 100;
9 | }
10 |
--------------------------------------------------------------------------------
/src/pages/geofence-list/geofence-list.ts:
--------------------------------------------------------------------------------
1 | import { Component } from "@angular/core";
2 | import { NavController, Platform, MenuController } from "ionic-angular";
3 | import { GeofenceDetailsPage } from "../geofence-details/geofence-details";
4 | import { GeofenceService } from "../../services/geofence-service";
5 | import { Splashscreen } from "ionic-native";
6 |
7 | @Component({
8 | templateUrl: "geofence-list.html"
9 | })
10 | export class GeofenceListPage {
11 | isLoading: boolean = false;
12 | geofences: [Geofence];
13 |
14 | constructor(
15 | private nav: NavController,
16 | private geofenceService: GeofenceService,
17 | private platform: Platform,
18 | private menu: MenuController
19 | ) {
20 | this.isLoading = true;
21 | this.platform.ready().then(() => {
22 | this.geofenceService.findAll()
23 | .then(geofences => {
24 | this.geofences = geofences;
25 | this.isLoading = false;
26 | })
27 | .catch(() => this.isLoading = false);
28 | });
29 | }
30 |
31 | ionViewDidEnter() {
32 | this.menu.enable(true);
33 | }
34 |
35 | ionViewDidLoad() {
36 | this.platform.ready().then(() => {
37 | Splashscreen.hide();
38 | });
39 | }
40 |
41 | new() {
42 | navigator.geolocation.getCurrentPosition(
43 | (position) => {
44 | const geofence = this.geofenceService.create({
45 | longitude: position.coords.longitude,
46 | latitude: position.coords.latitude,
47 | });
48 |
49 | this.transitionToDetailsPage(geofence);
50 | },
51 | (error) => {
52 |
53 | },
54 | { timeout: 5000 }
55 | );
56 | }
57 |
58 | geofenceItemTapped(geofence) {
59 | this.transitionToDetailsPage(geofence);
60 | }
61 |
62 | transitionToDetailsPage(geofence) {
63 | this.nav.push(GeofenceDetailsPage, {
64 | geofence
65 | })
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/service-worker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Check out https://googlechrome.github.io/sw-toolbox/docs/master/index.html for
3 | * more info on how to use sw-toolbox to custom configure your service worker.
4 | */
5 |
6 |
7 | 'use strict';
8 | importScripts('./build/sw-toolbox.js');
9 |
10 | self.toolbox.options.cache = {
11 | name: 'ionic-cache'
12 | };
13 |
14 | // pre-cache our key assets
15 | self.toolbox.precache(
16 | [
17 | './build/main.js',
18 | './build/main.css',
19 | './build/polyfills.js',
20 | 'index.html',
21 | 'manifest.json'
22 | ]
23 | );
24 |
25 | // dynamically cache any other local assets
26 | self.toolbox.router.any('/*', self.toolbox.cacheFirst);
27 |
28 | // for any other requests go to the network, cache,
29 | // and then only use that cached resource if your user goes offline
30 | self.toolbox.router.default = self.toolbox.networkFirst;
--------------------------------------------------------------------------------
/src/services/geofence-plugin-mock.ts:
--------------------------------------------------------------------------------
1 | import { FIXTURES } from "../models/geofence";
2 |
3 | export const GeofencePluginMock = {
4 | addOrUpdate(fences) {
5 | console.log("Mocked geofence plugin addOrUpdate", fences);
6 |
7 | return Promise.resolve();
8 | },
9 | getWatched() {
10 | return Promise.resolve(JSON.stringify(FIXTURES));
11 | },
12 | remove(ids) {
13 | console.log("Mocked geofence plugin remove", ids);
14 |
15 | return Promise.resolve();
16 | },
17 | removeAll() {
18 | console.log("Mocked geofence plugin removeAll");
19 |
20 | return Promise.resolve();
21 | },
22 | initialize() {
23 | console.log("Mocked geofence plugin initialize");
24 |
25 | return Promise.resolve();
26 | },
27 | onTransitionReceived() {
28 | console.log("Mocked geofence plugin onTransitionReceived");
29 | },
30 | onNotificationClicked() {
31 | console.log("Mocked geofence plugin onNotificationclicked");
32 | }
33 | };
34 |
35 | export const TransitionType = {
36 | ENTER: 1,
37 | EXIT: 2,
38 | BOTH: 3,
39 | }
40 |
--------------------------------------------------------------------------------
/src/services/geofence-service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from "@angular/core";
2 | import generateUUID from "../utils/uuid";
3 |
4 | @Injectable()
5 | export class GeofenceService {
6 | private geofences: Geofence[];
7 |
8 | create(attributes) {
9 | const defaultGeofence = {
10 | id: generateUUID(),
11 | latitude: 50,
12 | longitude: 50,
13 | radius: 1000,
14 | transitionType: window.TransitionType.ENTER,
15 | notification: {
16 | id: this.getNextNotificationId(),
17 | title: "Ionic geofence example",
18 | text: "",
19 | icon: "res://ic_menu_mylocation",
20 | openAppOnClick: true,
21 | },
22 | };
23 |
24 | return Object.assign(defaultGeofence, attributes);
25 | }
26 |
27 | clone(geofence: Geofence) {
28 | return JSON.parse(JSON.stringify(geofence));
29 | }
30 |
31 | addOrUpdate(geofence: Geofence) {
32 | return window.geofence.addOrUpdate(geofence)
33 | .then(() => this.findById(geofence.id))
34 | .then((found) => {
35 | if (!found) {
36 | this.geofences.push(geofence);
37 | } else {
38 | const index = this.geofences.indexOf(found);
39 |
40 | this.geofences[index] = geofence;
41 | }
42 | });
43 | }
44 |
45 | findAll() {
46 | return window.geofence.getWatched()
47 | .then((geofencesJson) => {
48 | const geofences = JSON.parse(geofencesJson);
49 |
50 | this.geofences = geofences;
51 | return geofences;
52 | });
53 | }
54 |
55 | findById(id) {
56 | const found = this.geofences.filter(g => g.id === id);
57 |
58 | if (found.length > 0) {
59 | return found[0];
60 | }
61 |
62 | return undefined;
63 | }
64 |
65 | removeAll() {
66 | return window.geofence.removeAll().then(() => {
67 | this.geofences.length = 0;
68 | });
69 | }
70 |
71 | remove(geofence) {
72 | return window.geofence.remove(geofence.id).then(() => {
73 | this.geofences.splice(this.geofences.indexOf(geofence), 1);
74 | });
75 | }
76 |
77 | private getNextNotificationId() {
78 | var max = 0;
79 |
80 | this.geofences.forEach(function (gf) {
81 | if (gf.notification && gf.notification.id) {
82 | if (gf.notification.id > max) {
83 | max = gf.notification.id;
84 | }
85 | }
86 | });
87 |
88 | return max + 1;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/theme/variables.scss:
--------------------------------------------------------------------------------
1 | // Ionic Variables and Theming. For more info, please see:
2 | // http://ionicframework.com/docs/v2/theming/
3 | $font-path: "../assets/fonts";
4 |
5 | @import "ionic.globals";
6 |
7 |
8 | // Shared Variables
9 | // --------------------------------------------------
10 | // To customize the look and feel of this app, you can override
11 | // the Sass variables found in Ionic's source scss files.
12 | // To view all the possible Ionic variables, see:
13 | // http://ionicframework.com/docs/v2/theming/overriding-ionic-variables/
14 |
15 |
16 |
17 |
18 | // Named Color Variables
19 | // --------------------------------------------------
20 | // Named colors makes it easy to reuse colors on various components.
21 | // It's highly recommended to change the default colors
22 | // to match your app's branding. Ionic uses a Sass map of
23 | // colors so you can add, rename and remove colors as needed.
24 | // The "primary" color is the only required color in the map.
25 |
26 | $colors: (
27 | primary: #387ef5,
28 | secondary: #32db64,
29 | danger: #f53d3d,
30 | light: #f4f4f4,
31 | dark: #222
32 | );
33 |
34 |
35 | // App iOS Variables
36 | // --------------------------------------------------
37 | // iOS only Sass variables can go here
38 |
39 |
40 |
41 |
42 | // App Material Design Variables
43 | // --------------------------------------------------
44 | // Material Design only Sass variables can go here
45 |
46 |
47 |
48 |
49 | // App Windows Variables
50 | // --------------------------------------------------
51 | // Windows only Sass variables can go here
52 |
53 |
54 |
55 |
56 | // App Theme
57 | // --------------------------------------------------
58 | // Ionic apps can have different themes applied, which can
59 | // then be future customized. This import comes last
60 | // so that the above variables are used and Ionic's
61 | // default are overridden.
62 |
63 | @import "ionic.theme.default";
64 |
65 |
66 | // Ionicons
67 | // --------------------------------------------------
68 | // The premium icon font for Ionic. For more info, please see:
69 | // http://ionicframework.com/docs/v2/ionicons/
70 |
71 | @import "ionic.ionicons";
72 |
73 |
74 | // Fonts
75 | // --------------------------------------------------
76 |
77 | @import "roboto";
78 | @import "noto-sans";
79 |
--------------------------------------------------------------------------------
/src/utils/uuid.ts:
--------------------------------------------------------------------------------
1 | export default function() {
2 | var d = new Date().getTime();
3 | let uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
4 | let r = (d + Math.random()*16)%16 | 0;
5 | d = Math.floor(d/16);
6 |
7 | return (c == "x" ? r : (r&0x3|0x8)).toString(16);
8 | });
9 | return uuid;
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "lib": [
8 | "dom",
9 | "es2015"
10 | ],
11 | "module": "es2015",
12 | "moduleResolution": "node",
13 | "sourceMap": true,
14 | "target": "es5"
15 | },
16 | "include": [
17 | "src/**/*.ts",
18 | "typings/**/*.ts"
19 | ],
20 | "exclude": [
21 | "node_modules",
22 | "typings/main",
23 | "typings/main.d.ts"
24 | ],
25 | "compileOnSave": false,
26 | "atom": {
27 | "rewriteTsconfig": false
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-duplicate-variable": true,
4 | "no-unused-variable": [
5 | true
6 | ]
7 | },
8 | "rulesDirectory": [
9 | "node_modules/tslint-eslint-rules/dist/rules"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {},
3 | "devDependencies": {},
4 | "ambientDependencies": {
5 | "cordova-plugin-geofence": "file:../cordova/cordova-plugin-geofence/typings/cordova-plugin-geofence.d.ts",
6 | "leaflet": "registry:dt/leaflet#0.7.3+20160330160843"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/typings/globals/cordova-plugin-geofence/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/cowbell/cordova-plugin-geofence/master/typings/cordova-plugin-geofence.d.ts
3 | interface TransitionType {
4 | ENTER: number;
5 | EXIT: number;
6 | BOTH: number;
7 | }
8 |
9 | interface Window {
10 | geofence: GeofencePlugin;
11 | TransitionType: TransitionType;
12 | }
13 |
14 | interface GeofencePlugin {
15 | initialize(
16 | successCallback?: (result: any) => void,
17 | errorCallback?: (error: string) => void
18 | ): Promise;
19 |
20 | addOrUpdate(
21 | geofence: Geofence | Geofence[],
22 | successCallback?: (result: any) => void,
23 | errorCallback?: (error: string) => void
24 | ): Promise;
25 |
26 | remove(
27 | id: number | number[],
28 | successCallback?: (result: any) => void,
29 | errorCallback?: (error: string) => void
30 | ): Promise;
31 |
32 | removeAll(
33 | successCallback?: (result: any) => void,
34 | errorCallback?: (error: string) => void
35 | ): Promise;
36 |
37 | getWatched(
38 | successCallback?: (result: any) => void,
39 | errorCallback?: (error: string) => void
40 | ): Promise;
41 |
42 | onTransitionReceived: (geofences: Geofence[]) => void;
43 | onNotificationClicked: (notificationData: Object) => void;
44 | }
45 |
46 | interface Geofence {
47 | id: string;
48 | latitude: number;
49 | longitude: number;
50 | radius: number;
51 | transitionType: number;
52 | notification?: Notification;
53 | }
54 |
55 | interface Notification {
56 | id?: number;
57 | title?: string;
58 | text: string;
59 | smallIcon?: string;
60 | icon?: string;
61 | openAppOnClick?: boolean;
62 | vibration?: number[];
63 | data?: Object;
64 | }
65 |
--------------------------------------------------------------------------------
/typings/globals/cordova-plugin-geofence/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/cowbell/cordova-plugin-geofence/master/typings/cordova-plugin-geofence.d.ts",
5 | "raw": "github:cowbell/cordova-plugin-geofence/typings/cordova-plugin-geofence.d.ts",
6 | "typings": "https://raw.githubusercontent.com/cowbell/cordova-plugin-geofence/master/typings/cordova-plugin-geofence.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/typings/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------