├── .gitignore ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── demo-angular ├── app │ ├── App_Resources │ │ ├── Android │ │ │ ├── AndroidManifest.xml │ │ │ ├── app.gradle │ │ │ ├── drawable-hdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-ldpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-mdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-nodpi │ │ │ │ └── splash_screen.xml │ │ │ ├── drawable-xhdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── values-v21 │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ └── values │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ └── iOS │ │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── icon-29.png │ │ │ │ ├── icon-29@2x.png │ │ │ │ ├── icon-29@3x.png │ │ │ │ ├── icon-40.png │ │ │ │ ├── icon-40@2x.png │ │ │ │ ├── icon-40@3x.png │ │ │ │ ├── icon-60@2x.png │ │ │ │ ├── icon-60@3x.png │ │ │ │ ├── icon-76.png │ │ │ │ ├── icon-76@2x.png │ │ │ │ └── icon-83.5@2x.png │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.launchimage │ │ │ │ ├── Contents.json │ │ │ │ ├── Default-568h@2x.png │ │ │ │ ├── Default-667h@2x.png │ │ │ │ ├── Default-736h@3x.png │ │ │ │ ├── Default-Landscape.png │ │ │ │ ├── Default-Landscape@2x.png │ │ │ │ ├── Default-Landscape@3x.png │ │ │ │ ├── Default-Portrait.png │ │ │ │ ├── Default-Portrait@2x.png │ │ │ │ ├── Default.png │ │ │ │ └── Default@2x.png │ │ │ ├── LaunchScreen.AspectFill.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchScreen-AspectFill.png │ │ │ │ └── LaunchScreen-AspectFill@2x.png │ │ │ └── LaunchScreen.Center.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchScreen-Center.png │ │ │ │ └── LaunchScreen-Center@2x.png │ │ │ ├── Info.plist │ │ │ ├── LaunchScreen.storyboard │ │ │ └── build.xcconfig │ ├── app.component.html │ ├── app.component.ts │ ├── app.module.ts │ ├── main.aot.ts │ ├── main.ts │ └── package.json ├── node_modules │ └── nativescript-store-update ├── package-lock.json ├── package.json └── tsconfig.json ├── demo ├── app │ ├── App_Resources │ │ ├── Android │ │ │ ├── AndroidManifest.xml │ │ │ ├── app.gradle │ │ │ ├── drawable-hdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-ldpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-mdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-nodpi │ │ │ │ └── splash_screen.xml │ │ │ ├── drawable-xhdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── background.png │ │ │ │ ├── icon.png │ │ │ │ └── logo.png │ │ │ ├── values-v21 │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ └── values │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ └── iOS │ │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── icon-29.png │ │ │ │ ├── icon-29@2x.png │ │ │ │ ├── icon-29@3x.png │ │ │ │ ├── icon-40.png │ │ │ │ ├── icon-40@2x.png │ │ │ │ ├── icon-40@3x.png │ │ │ │ ├── icon-50.png │ │ │ │ ├── icon-50@2x.png │ │ │ │ ├── icon-57.png │ │ │ │ ├── icon-57@2x.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 │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.launchimage │ │ │ │ ├── Contents.json │ │ │ │ ├── Default-568h@2x.png │ │ │ │ ├── Default-667h@2x.png │ │ │ │ ├── Default-736h@3x.png │ │ │ │ ├── Default-Landscape.png │ │ │ │ ├── Default-Landscape@2x.png │ │ │ │ ├── Default-Landscape@3x.png │ │ │ │ ├── Default-Portrait.png │ │ │ │ ├── Default-Portrait@2x.png │ │ │ │ ├── Default.png │ │ │ │ └── Default@2x.png │ │ │ ├── LaunchScreen.AspectFill.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchScreen-AspectFill.png │ │ │ │ └── LaunchScreen-AspectFill@2x.png │ │ │ └── LaunchScreen.Center.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchScreen-Center.png │ │ │ │ └── LaunchScreen-Center@2x.png │ │ │ ├── Info.plist │ │ │ ├── LaunchScreen.storyboard │ │ │ └── build.xcconfig │ ├── app.ts │ ├── bundle-config.ts │ ├── main-page.ts │ ├── main-page.xml │ ├── main-view-model.ts │ ├── package.json │ ├── tests │ │ ├── app-store.helper.spec.js │ │ ├── google-play.helper.spec.js │ │ ├── locales.helper.sepc.js │ │ ├── response.helper.spec.js │ │ ├── store-update-android.spec.js │ │ ├── store-update-common.spec.js │ │ ├── store-update-ios.spec.js │ │ ├── tests.constants.spec.js │ │ └── version.helper.spec.js │ ├── vendor-platform.android.ts │ ├── vendor-platform.ios.ts │ ├── vendor-platform.ts │ └── vendor.ts ├── karma.conf.js ├── package-lock.json ├── package.json ├── references.d.ts ├── tsconfig.json └── webpack.config.js ├── prettier.config.js ├── publish ├── pack.sh ├── package.json └── publish.sh ├── src ├── .npmignore ├── constants │ ├── alert-types.ts │ ├── app-store.ts │ ├── google-play.ts │ ├── index.ts │ └── update-types.ts ├── helpers │ ├── app-store.helper.ts │ ├── google-play.helper.ts │ ├── index.ts │ ├── locales.helper.ts │ ├── response.helper.ts │ └── version.helper.ts ├── i18n │ ├── en.json │ ├── es.json │ └── fr.json ├── index.d.ts ├── interfaces │ ├── app-store-result.interface.ts │ ├── google-play-result.interface.ts │ ├── index.ts │ └── store-update.config.interface.ts ├── package.json ├── platforms │ ├── android │ │ ├── AndroidManifest.xml │ │ ├── README.md │ │ └── include.gradle │ └── ios │ │ ├── Info.plist │ │ ├── README.md │ │ └── build.xcconfig ├── references.d.ts ├── store-update.android.ts ├── store-update.common.ts ├── store-update.ios.ts └── tsconfig.json ├── tslint-prettier.config.js └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | *.js.map 3 | *.log 4 | *.d.ts 5 | *.nsbuildinfo 6 | *.DS_Store 7 | 8 | !/index.d.ts 9 | !/reference.d.ts 10 | !tslint-prettier.config.js 11 | !prettier.config.js 12 | !prettier.config.js 13 | !src/assign.helper.js 14 | 15 | demo/app/*.js 16 | !demo/app/tests/*.js 17 | demo/*.d.ts 18 | demo/platforms 19 | demo/hooks 20 | demo/node_modules 21 | demo-angular/app/*.js 22 | demo-angular/*.d.ts 23 | demo-angular/node_modules 24 | demo-angular/hooks 25 | demo-angular/platforms 26 | src/node_modules 27 | src/hooks 28 | *.tgz 29 | package-lock.json -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "tslint.configFile": "tslint.json", 3 | "tslint.nodePath": "src/node_modules" 4 | } 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 1.0.2 (March 05, 2018) 2 | =================== 3 | 4 | - **Replace delegate implimentation with app resume** [Thanks to sitefinitysteve](https://github.com/sitefinitysteve) 5 | - **Allow dialog message customisation** [Thanks to sitefinitysteve](https://github.com/sitefinitysteve) 6 | - **Add `es` default translation** [Thanks to codeback](https://github.com/codeback) 7 | 8 | 1.0.1 (October 18, 2017) 9 | =================== 10 | 11 | **Remove references to nativescript-i18n plugin** 12 | 13 | 1.0.0 (October 12, 2017) 14 | =================== 15 | 16 | **Initial release** 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nativescript-store-update 2 | 3 | [![npm](https://img.shields.io/npm/v/nativescript-store-update.svg)](https://www.npmjs.com/package/nativescript-store-update) 4 | [![npm](https://img.shields.io/npm/dt/nativescript-store-update.svg?label=npm%20downloads)](https://www.npmjs.com/package/nativescript-store-update) 5 | 6 | [![NPM](https://nodei.co/npm/nativescript-store-update.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/nativescript-store-update/) 7 | 8 | This plugin allows you to define a notification strategy regarding your app updates. You are able to specify if you want to force, offer or ignore an update based on the new version available in the platform store. 9 | 10 | For example, you could want to force all major version update, but offer the option to your user to chose to update or skip a minor or patch version. 11 | 12 | You can also specify how many days after the update release you want to display the alert. 13 | 14 | ## Prerequisites 15 | 16 | You need to add appversion plugins for this one to work: 17 | ```zsh 18 | tns plugin add @nativescript/appversion 19 | ``` 20 | 21 | ## Installation 22 | 23 | ```zsh 24 | tns plugin add nativescript-store-update 25 | ``` 26 | 27 | ## Usage 28 | 29 | In your `main.ts` or `app.ts` file, before app start, call `StoreUpdate.init` with desired options like so: 30 | 31 | ``` javascript 32 | import { StoreUpdate, AlertTypesConstants } from "nativescript-store-update"; 33 | 34 | StoreUpdate.init({ 35 | notifyNbDaysAfterRelease: 1, 36 | majorUpdateAlertType: AlertTypesConstants.OPTION 37 | }) 38 | ``` 39 | 40 | ## Localization 41 | 42 | The plugin contains some default translations inside json files located in `src/i18n` folder and required by hand in the `src/helpers/locales.helper.ts` file. 43 | You can also specify a custom translation in the plugin initialization through the configuraiton options. 44 | If you want to contribute a regionalized translation, you must use the `lang-regionCode` format specified in [Apple doc](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html), but with the country lowercased (ex: `fr-ca`, `en-us`) 45 | 46 | 47 | ## API 48 | 49 | ### Configuration options 50 | | Property | Default | Description | 51 | | --- | --- | --- | 52 | | **majorUpdateAlertType** | FORCE | Alert type for major version change (e.g: A.b.c.d) | 53 | | **minorUpdateAlertType** | OPTION | Alert type for minor version change (e.g: a.B.c.d) | 54 | | **patchUpdateAlertType** | NONE | Alert type for major version change (e.g: a.b.C.d) | 55 | | **revisionUpdateAlertType** | NONE | Alert type for revision version change (e.g: a.b.c.D) | 56 | | **notifyNbDaysAfterRelease** | `1` | Delays the update prompt by a specific number of days | 57 | | **countryCode** | `en` | country store code | 58 | | **alertOptions** | null | Customize alert dialog text, bypasses the Locale json | 59 | 60 | ### Alert types 61 | | Key | Value | Description | 62 | | --- | --- | --- | 63 | | **FORCE** | `1` | Show an alert that can't be skipped | 64 | | **OPTION** | `2` | Show an alert that can be skipped | 65 | | **NONE** | `3` | Don't display alert at all | 66 | 67 | ### AlertOptions configuration (Optional) 68 | | Property | Default | Description | 69 | | --- | --- | --- | 70 | | **title** | LocaleText | Dialog title, fallback to the locale json | 71 | | **message** | LocaleText | Dialog body text, fallback to the locale json | 72 | | **updateButton** | LocaleText | Dialog update button, fallback to the locale json | 73 | | **skipButton** | LocaleText | Dialog skip button, fallback to the locale json | 74 | 75 | ## Development 76 | 77 | Clone this repository, go in the `src` folder then run the command `npm run setup` 78 | You can then use: 79 | - `npm run demo.ios` or `npm run demo.android` to start the demo 80 | - `npm run plugin.tscwatch` to watch plugin file and start developing! 81 | 82 | The repo contains 2 demos folder, one with angular, and one without. 83 | Demos use the bundleId `com.bitstrips.imoji` as their App version contains Major, Minor and Patch numbers, and they update their app really often. 84 | You can change parameters passed ton package init in `main.ts` or `app.ts` files and change app version in android `app.gradle` and ios `info.plist` config files to test the feature. 85 | 86 | ## License 87 | 88 | Apache License Version 2.0, January 2004 89 | 90 | 91 | ## Contributors 92 | - [Jérémy Pelé](https://github.com/jeremypele) 93 | - [Simon Bats](https://github.com/SBats) 94 | - [Steve McNiven-Scott](https://github.com/sitefinitysteve) 95 | - [Codeback Software](https://github.com/codeback) 96 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/app.gradle: -------------------------------------------------------------------------------- 1 | // Add your native dependencies here: 2 | 3 | // Uncomment to add recyclerview-v7 dependency 4 | //dependencies { 5 | // compile 'com.android.support:recyclerview-v7:+' 6 | //} 7 | 8 | android { 9 | defaultConfig { 10 | generatedDensities = [] 11 | applicationId = "com.bitstrips.imoji" 12 | } 13 | aaptOptions { 14 | additionalParameters "--no-version-vectors" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-hdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-hdpi/background.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-hdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-hdpi/logo.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-ldpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-ldpi/background.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-ldpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-ldpi/logo.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-mdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-mdpi/background.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-mdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-mdpi/logo.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-nodpi/splash_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-xhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-xhdpi/background.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-xhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-xhdpi/logo.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-xxhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-xxhdpi/background.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-xxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-xxhdpi/logo.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-xxxhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-xxxhdpi/background.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-xxxhdpi/icon.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/drawable-xxxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/Android/drawable-xxxhdpi/logo.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/values-v21/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3d5afe 4 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 14 | 15 | 16 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #F5F5F5 4 | #757575 5 | #33B5E5 6 | #272734 7 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/Android/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | 21 | 22 | 23 | 31 | 32 | 34 | 35 | 36 | 42 | 43 | 45 | 46 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "icon-29.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "icon-29@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon-29@3x.png", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "icon-40@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon-40@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "icon-60@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "icon-60@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "29x29", 47 | "idiom" : "ipad", 48 | "filename" : "icon-29.png", 49 | "scale" : "1x" 50 | }, 51 | { 52 | "size" : "29x29", 53 | "idiom" : "ipad", 54 | "filename" : "icon-29@2x.png", 55 | "scale" : "2x" 56 | }, 57 | { 58 | "size" : "40x40", 59 | "idiom" : "ipad", 60 | "filename" : "icon-40.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "40x40", 65 | "idiom" : "ipad", 66 | "filename" : "icon-40@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "76x76", 71 | "idiom" : "ipad", 72 | "filename" : "icon-76.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "76x76", 77 | "idiom" : "ipad", 78 | "filename" : "icon-76@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "83.5x83.5", 83 | "idiom" : "ipad", 84 | "filename" : "icon-83.5@2x.png", 85 | "scale" : "2x" 86 | } 87 | ], 88 | "info" : { 89 | "version" : 1, 90 | "author" : "xcode" 91 | } 92 | } -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "Default-736h@3x.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "736h", 16 | "filename" : "Default-Landscape@3x.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "landscape", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "extent" : "full-screen", 23 | "idiom" : "iphone", 24 | "subtype" : "667h", 25 | "filename" : "Default-667h@2x.png", 26 | "minimum-system-version" : "8.0", 27 | "orientation" : "portrait", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "orientation" : "portrait", 32 | "idiom" : "iphone", 33 | "filename" : "Default@2x.png", 34 | "extent" : "full-screen", 35 | "minimum-system-version" : "7.0", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "extent" : "full-screen", 40 | "idiom" : "iphone", 41 | "subtype" : "retina4", 42 | "filename" : "Default-568h@2x.png", 43 | "minimum-system-version" : "7.0", 44 | "orientation" : "portrait", 45 | "scale" : "2x" 46 | }, 47 | { 48 | "orientation" : "portrait", 49 | "idiom" : "ipad", 50 | "filename" : "Default-Portrait.png", 51 | "extent" : "full-screen", 52 | "minimum-system-version" : "7.0", 53 | "scale" : "1x" 54 | }, 55 | { 56 | "orientation" : "landscape", 57 | "idiom" : "ipad", 58 | "filename" : "Default-Landscape.png", 59 | "extent" : "full-screen", 60 | "minimum-system-version" : "7.0", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "orientation" : "portrait", 65 | "idiom" : "ipad", 66 | "filename" : "Default-Portrait@2x.png", 67 | "extent" : "full-screen", 68 | "minimum-system-version" : "7.0", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "orientation" : "landscape", 73 | "idiom" : "ipad", 74 | "filename" : "Default-Landscape@2x.png", 75 | "extent" : "full-screen", 76 | "minimum-system-version" : "7.0", 77 | "scale" : "2x" 78 | }, 79 | { 80 | "orientation" : "portrait", 81 | "idiom" : "iphone", 82 | "filename" : "Default.png", 83 | "extent" : "full-screen", 84 | "scale" : "1x" 85 | }, 86 | { 87 | "orientation" : "portrait", 88 | "idiom" : "iphone", 89 | "filename" : "Default@2x.png", 90 | "extent" : "full-screen", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "orientation" : "portrait", 95 | "idiom" : "iphone", 96 | "filename" : "Default-568h@2x.png", 97 | "extent" : "full-screen", 98 | "subtype" : "retina4", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "orientation" : "portrait", 103 | "idiom" : "ipad", 104 | "extent" : "to-status-bar", 105 | "scale" : "1x" 106 | }, 107 | { 108 | "orientation" : "portrait", 109 | "idiom" : "ipad", 110 | "filename" : "Default-Portrait.png", 111 | "extent" : "full-screen", 112 | "scale" : "1x" 113 | }, 114 | { 115 | "orientation" : "landscape", 116 | "idiom" : "ipad", 117 | "extent" : "to-status-bar", 118 | "scale" : "1x" 119 | }, 120 | { 121 | "orientation" : "landscape", 122 | "idiom" : "ipad", 123 | "filename" : "Default-Landscape.png", 124 | "extent" : "full-screen", 125 | "scale" : "1x" 126 | }, 127 | { 128 | "orientation" : "portrait", 129 | "idiom" : "ipad", 130 | "extent" : "to-status-bar", 131 | "scale" : "2x" 132 | }, 133 | { 134 | "orientation" : "portrait", 135 | "idiom" : "ipad", 136 | "filename" : "Default-Portrait@2x.png", 137 | "extent" : "full-screen", 138 | "scale" : "2x" 139 | }, 140 | { 141 | "orientation" : "landscape", 142 | "idiom" : "ipad", 143 | "extent" : "to-status-bar", 144 | "scale" : "2x" 145 | }, 146 | { 147 | "orientation" : "landscape", 148 | "idiom" : "ipad", 149 | "filename" : "Default-Landscape@2x.png", 150 | "extent" : "full-screen", 151 | "scale" : "2x" 152 | } 153 | ], 154 | "info" : { 155 | "version" : 1, 156 | "author" : "xcode" 157 | } 158 | } -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchScreen-AspectFill.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchScreen-AspectFill@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchScreen-Center.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchScreen-Center@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo-angular/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.1.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiresFullScreen 28 | 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 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 | -------------------------------------------------------------------------------- /demo-angular/app/App_Resources/iOS/build.xcconfig: -------------------------------------------------------------------------------- 1 | // You can add custom settings here 2 | // for example you can uncomment the following line to force distribution code signing 3 | // CODE_SIGN_IDENTITY = iPhone Distribution 4 | // To build for device with Xcode 8 you need to specify your development team. More info: https://developer.apple.com/library/prerelease/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html 5 | // DEVELOPMENT_TEAM = YOUR_TEAM_ID; 6 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 7 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 8 | -------------------------------------------------------------------------------- /demo-angular/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo-angular/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | 3 | @Component({ 4 | selector: 'ns-app', 5 | templateUrl: 'app.component.html', 6 | }) 7 | export class AppComponent {} 8 | -------------------------------------------------------------------------------- /demo-angular/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core' 2 | import { NativeScriptModule } from 'nativescript-angular/nativescript.module' 3 | import { AppComponent } from './app.component' 4 | 5 | // Uncomment and add to NgModule imports if you need to use two-way binding 6 | // import { NativeScriptFormsModule } from "nativescript-angular/forms"; 7 | 8 | // Uncomment and add to NgModule imports if you need to use the HTTP wrapper 9 | // import { NativeScriptHttpModule } from "nativescript-angular/http"; 10 | 11 | @NgModule({ 12 | bootstrap: [AppComponent], 13 | declarations: [AppComponent], 14 | imports: [NativeScriptModule], 15 | schemas: [NO_ERRORS_SCHEMA], 16 | }) 17 | /* 18 | Pass your application module to the bootstrapModule function located in main.ts to start your app 19 | */ 20 | export class AppModule {} 21 | -------------------------------------------------------------------------------- /demo-angular/app/main.aot.ts: -------------------------------------------------------------------------------- 1 | // this import should be first in order to load some required settings (like globals and reflect-metadata) 2 | import { platformNativeScript } from 'nativescript-angular/platform-static' 3 | import { StoreUpdate } from 'nativescript-store-update' 4 | import { AppModuleNgFactory } from './app.module.ngfactory' 5 | 6 | StoreUpdate.init({ 7 | notifyNbDaysAfterRelease: 1, 8 | }) 9 | platformNativeScript().bootstrapModuleFactory(AppModuleNgFactory) 10 | -------------------------------------------------------------------------------- /demo-angular/app/main.ts: -------------------------------------------------------------------------------- 1 | // this import should be first in order to load some required settings (like globals and reflect-metadata) 2 | import { platformNativeScriptDynamic } from 'nativescript-angular/platform' 3 | import { AlertTypesConstants, StoreUpdate } from 'nativescript-store-update' 4 | import { AppModule } from './app.module' 5 | 6 | StoreUpdate.init({ 7 | majorUpdateAlertType: AlertTypesConstants.OPTION, 8 | notifyNbDaysAfterRelease: 0, 9 | alertOptions: { 10 | title: 'Attention please', 11 | message: 'Your app is out of date', 12 | }, 13 | }) 14 | // A traditional NativeScript application starts by initializing global objects, setting up global CSS rules, creating, and navigating to the main page. 15 | // Angular applications need to take care of their own initialization: modules, components, directives, routes, DI providers. 16 | // A NativeScript Angular app needs to make both paradigms work together, so we provide a wrapper platform object, platformNativeScriptDynamic, 17 | // that sets up a NativeScript application and can bootstrap the Angular framework. 18 | platformNativeScriptDynamic().bootstrapModule(AppModule) 19 | -------------------------------------------------------------------------------- /demo-angular/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "android": { 3 | "v8Flags": "--expose_gc" 4 | }, 5 | "main": "main.js", 6 | "name": "tns-template-hello-world-ng", 7 | "version": "3.1.2" 8 | } -------------------------------------------------------------------------------- /demo-angular/node_modules/nativescript-store-update: -------------------------------------------------------------------------------- 1 | ../../src -------------------------------------------------------------------------------- /demo-angular/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@angular/animations": { 6 | "version": "4.2.6", 7 | "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-4.2.6.tgz", 8 | "integrity": "sha1-nZyAoRmwwDaTy9I7uvcosVMf/8c=", 9 | "requires": { 10 | "tslib": "1.7.1" 11 | } 12 | }, 13 | "@angular/common": { 14 | "version": "4.2.6", 15 | "resolved": "https://registry.npmjs.org/@angular/common/-/common-4.2.6.tgz", 16 | "integrity": "sha1-IQrOS9JON1+LQbpS/rNLGKiH1do=", 17 | "requires": { 18 | "tslib": "1.7.1" 19 | } 20 | }, 21 | "@angular/compiler": { 22 | "version": "4.2.6", 23 | "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.2.6.tgz", 24 | "integrity": "sha1-ZndW1JXKDUXSBhJooQ1Sr4Ofr/Q=", 25 | "requires": { 26 | "tslib": "1.7.1" 27 | } 28 | }, 29 | "@angular/core": { 30 | "version": "4.2.6", 31 | "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.2.6.tgz", 32 | "integrity": "sha1-DByP8BV/B29KfAtyHKFCPxu+Fk4=", 33 | "requires": { 34 | "tslib": "1.7.1" 35 | } 36 | }, 37 | "@angular/forms": { 38 | "version": "4.2.6", 39 | "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-4.2.6.tgz", 40 | "integrity": "sha1-nTI5lgjkYDu/GXQXqluU6ApGfrA=", 41 | "requires": { 42 | "tslib": "1.7.1" 43 | } 44 | }, 45 | "@angular/http": { 46 | "version": "4.2.6", 47 | "resolved": "https://registry.npmjs.org/@angular/http/-/http-4.2.6.tgz", 48 | "integrity": "sha1-SZ4roLvB89cbdt6+wDTJWMrxE04=", 49 | "requires": { 50 | "tslib": "1.7.1" 51 | } 52 | }, 53 | "@angular/platform-browser": { 54 | "version": "4.2.6", 55 | "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-4.2.6.tgz", 56 | "integrity": "sha1-oTH/WSIl/mSWvKLJr/YSpNvd9Dc=", 57 | "requires": { 58 | "tslib": "1.7.1" 59 | } 60 | }, 61 | "@angular/router": { 62 | "version": "4.2.6", 63 | "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.2.6.tgz", 64 | "integrity": "sha1-ppGdm2HEX/wV++5ZM5jj/VMtq0Y=", 65 | "requires": { 66 | "tslib": "1.7.1" 67 | } 68 | }, 69 | "ansi-regex": { 70 | "version": "2.1.1", 71 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 72 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 73 | "dev": true 74 | }, 75 | "ansi-styles": { 76 | "version": "2.2.1", 77 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 78 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 79 | "dev": true 80 | }, 81 | "babel-code-frame": { 82 | "version": "6.26.0", 83 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 84 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 85 | "dev": true, 86 | "requires": { 87 | "chalk": "1.1.3", 88 | "esutils": "2.0.2", 89 | "js-tokens": "3.0.2" 90 | } 91 | }, 92 | "babel-messages": { 93 | "version": "6.23.0", 94 | "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", 95 | "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", 96 | "dev": true, 97 | "requires": { 98 | "babel-runtime": "6.26.0" 99 | } 100 | }, 101 | "babel-runtime": { 102 | "version": "6.26.0", 103 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 104 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 105 | "dev": true, 106 | "requires": { 107 | "core-js": "2.5.0", 108 | "regenerator-runtime": "0.11.0" 109 | } 110 | }, 111 | "babel-traverse": { 112 | "version": "6.26.0", 113 | "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", 114 | "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", 115 | "dev": true, 116 | "requires": { 117 | "babel-code-frame": "6.26.0", 118 | "babel-messages": "6.23.0", 119 | "babel-runtime": "6.26.0", 120 | "babel-types": "6.26.0", 121 | "babylon": "6.18.0", 122 | "debug": "2.6.8", 123 | "globals": "9.18.0", 124 | "invariant": "2.2.2", 125 | "lodash": "4.17.4" 126 | } 127 | }, 128 | "babel-types": { 129 | "version": "6.26.0", 130 | "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", 131 | "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", 132 | "dev": true, 133 | "requires": { 134 | "babel-runtime": "6.26.0", 135 | "esutils": "2.0.2", 136 | "lodash": "4.17.4", 137 | "to-fast-properties": "1.0.3" 138 | } 139 | }, 140 | "babylon": { 141 | "version": "6.18.0", 142 | "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", 143 | "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", 144 | "dev": true 145 | }, 146 | "balanced-match": { 147 | "version": "1.0.0", 148 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 149 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 150 | "dev": true 151 | }, 152 | "brace-expansion": { 153 | "version": "1.1.8", 154 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 155 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 156 | "dev": true, 157 | "requires": { 158 | "balanced-match": "1.0.0", 159 | "concat-map": "0.0.1" 160 | } 161 | }, 162 | "chalk": { 163 | "version": "1.1.3", 164 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 165 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 166 | "dev": true, 167 | "requires": { 168 | "ansi-styles": "2.2.1", 169 | "escape-string-regexp": "1.0.5", 170 | "has-ansi": "2.0.0", 171 | "strip-ansi": "3.0.1", 172 | "supports-color": "2.0.0" 173 | } 174 | }, 175 | "concat-map": { 176 | "version": "0.0.1", 177 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 178 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 179 | "dev": true 180 | }, 181 | "core-js": { 182 | "version": "2.5.0", 183 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.0.tgz", 184 | "integrity": "sha1-VpwFCRi+ZIazg3VSAorgRmtxcIY=", 185 | "dev": true 186 | }, 187 | "debug": { 188 | "version": "2.6.8", 189 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", 190 | "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", 191 | "dev": true, 192 | "requires": { 193 | "ms": "2.0.0" 194 | } 195 | }, 196 | "escape-string-regexp": { 197 | "version": "1.0.5", 198 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 199 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 200 | "dev": true 201 | }, 202 | "esutils": { 203 | "version": "2.0.2", 204 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 205 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 206 | "dev": true 207 | }, 208 | "glob": { 209 | "version": "6.0.4", 210 | "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", 211 | "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", 212 | "dev": true, 213 | "requires": { 214 | "inflight": "1.0.6", 215 | "inherits": "2.0.3", 216 | "minimatch": "3.0.4", 217 | "once": "1.4.0", 218 | "path-is-absolute": "1.0.1" 219 | } 220 | }, 221 | "globals": { 222 | "version": "9.18.0", 223 | "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", 224 | "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", 225 | "dev": true 226 | }, 227 | "has-ansi": { 228 | "version": "2.0.0", 229 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 230 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 231 | "dev": true, 232 | "requires": { 233 | "ansi-regex": "2.1.1" 234 | } 235 | }, 236 | "inflight": { 237 | "version": "1.0.6", 238 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 239 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 240 | "dev": true, 241 | "requires": { 242 | "once": "1.4.0", 243 | "wrappy": "1.0.2" 244 | } 245 | }, 246 | "inherits": { 247 | "version": "2.0.3", 248 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 249 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 250 | "dev": true 251 | }, 252 | "invariant": { 253 | "version": "2.2.2", 254 | "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", 255 | "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", 256 | "dev": true, 257 | "requires": { 258 | "loose-envify": "1.3.1" 259 | } 260 | }, 261 | "js-tokens": { 262 | "version": "3.0.2", 263 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 264 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 265 | "dev": true 266 | }, 267 | "lazy": { 268 | "version": "1.0.11", 269 | "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", 270 | "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=", 271 | "dev": true 272 | }, 273 | "lodash": { 274 | "version": "4.17.4", 275 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 276 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", 277 | "dev": true 278 | }, 279 | "loose-envify": { 280 | "version": "1.3.1", 281 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", 282 | "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", 283 | "dev": true, 284 | "requires": { 285 | "js-tokens": "3.0.2" 286 | } 287 | }, 288 | "minimatch": { 289 | "version": "3.0.4", 290 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 291 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 292 | "dev": true, 293 | "requires": { 294 | "brace-expansion": "1.1.8" 295 | } 296 | }, 297 | "minimist": { 298 | "version": "0.0.8", 299 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 300 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 301 | "dev": true 302 | }, 303 | "mkdirp": { 304 | "version": "0.5.1", 305 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 306 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 307 | "dev": true, 308 | "requires": { 309 | "minimist": "0.0.8" 310 | } 311 | }, 312 | "ms": { 313 | "version": "2.0.0", 314 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 315 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 316 | "dev": true 317 | }, 318 | "nativescript-angular": { 319 | "version": "4.2.0", 320 | "resolved": "https://registry.npmjs.org/nativescript-angular/-/nativescript-angular-4.2.0.tgz", 321 | "integrity": "sha512-I7iSIW1NQGJRGM96mkPjngJD3b64l8aRlMdcgdJ8gf2B1S1BGhk5IBdu4lhfwjdUSlv4x80QQHhWaAJrRQyslA==", 322 | "requires": { 323 | "nativescript-intl": "3.0.0", 324 | "reflect-metadata": "0.1.10" 325 | } 326 | }, 327 | "nativescript-appversion": { 328 | "version": "1.4.1", 329 | "resolved": "https://registry.npmjs.org/nativescript-appversion/-/nativescript-appversion-1.4.1.tgz", 330 | "integrity": "sha1-OpAo4zx35VVTlhk9KLweerdmG40=" 331 | }, 332 | "nativescript-dev-typescript": { 333 | "version": "0.5.0", 334 | "resolved": "https://registry.npmjs.org/nativescript-dev-typescript/-/nativescript-dev-typescript-0.5.0.tgz", 335 | "integrity": "sha1-EqOcRRN6Wh8/qxIhYZldinrOECU=", 336 | "dev": true, 337 | "requires": { 338 | "nativescript-hook": "0.2.1" 339 | } 340 | }, 341 | "nativescript-hook": { 342 | "version": "0.2.1", 343 | "resolved": "https://registry.npmjs.org/nativescript-hook/-/nativescript-hook-0.2.1.tgz", 344 | "integrity": "sha1-eGIlBW2yD6SeeGRR3M1ktS44ZNk=", 345 | "dev": true, 346 | "requires": { 347 | "glob": "6.0.4", 348 | "mkdirp": "0.5.1" 349 | } 350 | }, 351 | "nativescript-intl": { 352 | "version": "3.0.0", 353 | "resolved": "https://registry.npmjs.org/nativescript-intl/-/nativescript-intl-3.0.0.tgz", 354 | "integrity": "sha1-gu6b59N3Fys8QpVzRyMDdijhhqc=" 355 | }, 356 | "nativescript-store-update": { 357 | "version": "file:../src", 358 | "requires": { 359 | "@types/moment": "2.13.0", 360 | "moment": "2.18.1", 361 | "nativescript-appversion": "1.4.1" 362 | }, 363 | "dependencies": { 364 | "@angular/core": { 365 | "version": "4.3.6", 366 | "bundled": true 367 | }, 368 | "@types/moment": { 369 | "version": "2.13.0", 370 | "bundled": true, 371 | "requires": { 372 | "moment": "2.18.1" 373 | } 374 | }, 375 | "async": { 376 | "version": "0.9.2", 377 | "bundled": true 378 | }, 379 | "cycle": { 380 | "version": "1.0.3", 381 | "bundled": true 382 | }, 383 | "deep-equal": { 384 | "version": "0.2.2", 385 | "bundled": true 386 | }, 387 | "eyes": { 388 | "version": "0.1.8", 389 | "bundled": true 390 | }, 391 | "i": { 392 | "version": "0.3.5", 393 | "bundled": true 394 | }, 395 | "isstream": { 396 | "version": "0.1.2", 397 | "bundled": true 398 | }, 399 | "moment": { 400 | "version": "2.18.1", 401 | "bundled": true 402 | }, 403 | "mute-stream": { 404 | "version": "0.0.7", 405 | "bundled": true 406 | }, 407 | "nativescript-appversion": { 408 | "version": "1.4.1", 409 | "bundled": true 410 | }, 411 | "ncp": { 412 | "version": "1.0.1", 413 | "bundled": true 414 | }, 415 | "pkginfo": { 416 | "version": "0.4.0", 417 | "bundled": true 418 | }, 419 | "prompt": { 420 | "version": "1.0.0", 421 | "bundled": true, 422 | "requires": { 423 | "pkginfo": "0.4.0", 424 | "read": "1.0.7", 425 | "revalidator": "0.1.8", 426 | "utile": "0.3.0", 427 | "winston": "2.1.1" 428 | } 429 | }, 430 | "read": { 431 | "version": "1.0.7", 432 | "bundled": true, 433 | "requires": { 434 | "mute-stream": "0.0.7" 435 | } 436 | }, 437 | "revalidator": { 438 | "version": "0.1.8", 439 | "bundled": true 440 | }, 441 | "rimraf": { 442 | "version": "2.6.1", 443 | "bundled": true 444 | }, 445 | "rxjs": { 446 | "version": "5.4.3", 447 | "bundled": true, 448 | "requires": { 449 | "symbol-observable": "1.0.4" 450 | } 451 | }, 452 | "stack-trace": { 453 | "version": "0.0.10", 454 | "bundled": true 455 | }, 456 | "symbol-observable": { 457 | "version": "1.0.4", 458 | "bundled": true 459 | }, 460 | "tns-platform-declarations": { 461 | "version": "3.1.1", 462 | "bundled": true 463 | }, 464 | "typescript": { 465 | "version": "2.3.4", 466 | "bundled": true 467 | }, 468 | "utile": { 469 | "version": "0.3.0", 470 | "bundled": true, 471 | "requires": { 472 | "async": "0.9.2", 473 | "deep-equal": "0.2.2", 474 | "i": "0.3.5", 475 | "ncp": "1.0.1", 476 | "rimraf": "2.6.1" 477 | } 478 | }, 479 | "winston": { 480 | "version": "2.1.1", 481 | "bundled": true, 482 | "requires": { 483 | "async": "1.0.0", 484 | "colors": "1.0.3", 485 | "cycle": "1.0.3", 486 | "eyes": "0.1.8", 487 | "isstream": "0.1.2", 488 | "pkginfo": "0.3.1", 489 | "stack-trace": "0.0.10" 490 | }, 491 | "dependencies": { 492 | "async": { 493 | "version": "1.0.0", 494 | "bundled": true 495 | }, 496 | "colors": { 497 | "version": "1.0.3", 498 | "bundled": true 499 | }, 500 | "pkginfo": { 501 | "version": "0.3.1", 502 | "bundled": true 503 | } 504 | } 505 | }, 506 | "zone.js": { 507 | "version": "0.8.17", 508 | "bundled": true 509 | } 510 | } 511 | }, 512 | "once": { 513 | "version": "1.4.0", 514 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 515 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 516 | "dev": true, 517 | "requires": { 518 | "wrappy": "1.0.2" 519 | } 520 | }, 521 | "path-is-absolute": { 522 | "version": "1.0.1", 523 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 524 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 525 | "dev": true 526 | }, 527 | "reflect-metadata": { 528 | "version": "0.1.10", 529 | "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.10.tgz", 530 | "integrity": "sha1-tPg3BEFqytiZiMmxVjXUfgO5NEo=" 531 | }, 532 | "regenerator-runtime": { 533 | "version": "0.11.0", 534 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", 535 | "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", 536 | "dev": true 537 | }, 538 | "rxjs": { 539 | "version": "5.4.3", 540 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz", 541 | "integrity": "sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==", 542 | "requires": { 543 | "symbol-observable": "1.0.4" 544 | } 545 | }, 546 | "strip-ansi": { 547 | "version": "3.0.1", 548 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 549 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 550 | "dev": true, 551 | "requires": { 552 | "ansi-regex": "2.1.1" 553 | } 554 | }, 555 | "supports-color": { 556 | "version": "2.0.0", 557 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 558 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 559 | "dev": true 560 | }, 561 | "symbol-observable": { 562 | "version": "1.0.4", 563 | "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", 564 | "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=" 565 | }, 566 | "tns-core-modules": { 567 | "version": "3.1.1", 568 | "resolved": "https://registry.npmjs.org/tns-core-modules/-/tns-core-modules-3.1.1.tgz", 569 | "integrity": "sha1-ezicQt1sENstGt+8bJEDFwPlDdU=", 570 | "requires": { 571 | "tns-core-modules-widgets": "3.1.1" 572 | } 573 | }, 574 | "tns-core-modules-widgets": { 575 | "version": "3.1.1", 576 | "resolved": "https://registry.npmjs.org/tns-core-modules-widgets/-/tns-core-modules-widgets-3.1.1.tgz", 577 | "integrity": "sha1-M2691nlV6Im5GNsuzyRy/rVwh+A=" 578 | }, 579 | "to-fast-properties": { 580 | "version": "1.0.3", 581 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", 582 | "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", 583 | "dev": true 584 | }, 585 | "tslib": { 586 | "version": "1.7.1", 587 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz", 588 | "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=" 589 | }, 590 | "typescript": { 591 | "version": "2.4.2", 592 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.4.2.tgz", 593 | "integrity": "sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ=", 594 | "dev": true 595 | }, 596 | "wrappy": { 597 | "version": "1.0.2", 598 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 599 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 600 | "dev": true 601 | }, 602 | "zone.js": { 603 | "version": "0.8.17", 604 | "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.17.tgz", 605 | "integrity": "sha1-TF5RhahX2o2nk9rzkZNxxaNrKgs=" 606 | } 607 | } 608 | } 609 | -------------------------------------------------------------------------------- /demo-angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "NativeScript Application", 3 | "license": "SEE LICENSE IN ", 4 | "readme": "NativeScript Application", 5 | "repository": "", 6 | "nativescript": { 7 | "id": "com.bitstrips.imoji", 8 | "tns-android": { 9 | "version": "3.2.0" 10 | }, 11 | "tns-ios": { 12 | "version": "3.2.0" 13 | } 14 | }, 15 | "dependencies": { 16 | "@angular/animations": "~4.2.0", 17 | "@angular/common": "~4.2.0", 18 | "@angular/compiler": "~4.2.0", 19 | "@angular/core": "~4.2.0", 20 | "@angular/forms": "~4.2.0", 21 | "@angular/http": "~4.2.0", 22 | "@angular/platform-browser": "~4.2.0", 23 | "@angular/router": "~4.2.0", 24 | "nativescript-angular": "~4.2.0", 25 | "nativescript-appversion": "^1.4.1", 26 | "nativescript-store-update": "file:../src", 27 | "reflect-metadata": "~0.1.8", 28 | "rxjs": "~5.4.2", 29 | "tns-core-modules": "~3.1.0", 30 | "zone.js": "~0.8.2" 31 | }, 32 | "devDependencies": { 33 | "babel-traverse": "6.26.0", 34 | "babel-types": "6.26.0", 35 | "babylon": "6.18.0", 36 | "lazy": "1.0.11", 37 | "nativescript-dev-typescript": "~0.5.0", 38 | "typescript": "~2.4.2" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /demo-angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "experimentalDecorators": true, 6 | "emitDecoratorMetadata": true, 7 | "noEmitHelpers": true, 8 | "noEmitOnError": true, 9 | "lib": [ 10 | "es6", 11 | "dom", 12 | "es2015.iterable" 13 | ], 14 | "baseUrl": ".", 15 | "paths": { 16 | "*": [ 17 | "./node_modules/tns-core-modules/*", 18 | "./node_modules/*" 19 | ] 20 | } 21 | }, 22 | "exclude": [ 23 | "node_modules", 24 | "platforms", 25 | "**/*.aot.ts" 26 | ] 27 | } -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/app.gradle: -------------------------------------------------------------------------------- 1 | // Add your native dependencies here: 2 | 3 | // Uncomment to add recyclerview-v7 dependency 4 | //dependencies { 5 | // compile 'com.android.support:recyclerview-v7:+' 6 | //} 7 | 8 | android { 9 | defaultConfig { 10 | generatedDensities = [] 11 | applicationId = "com.bitstrips.imoji" 12 | } 13 | aaptOptions { 14 | additionalParameters "--no-version-vectors" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-hdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-hdpi/background.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-hdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-hdpi/logo.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-ldpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-ldpi/background.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-ldpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-ldpi/logo.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-mdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-mdpi/background.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-mdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-mdpi/logo.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-nodpi/splash_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-xhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-xhdpi/background.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-xhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-xhdpi/logo.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-xxhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-xxhdpi/background.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-xxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-xxhdpi/logo.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-xxxhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-xxxhdpi/background.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-xxxhdpi/icon.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/drawable-xxxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/Android/drawable-xxxhdpi/logo.png -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/values-v21/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3d5afe 4 | -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 14 | 15 | 16 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #F5F5F5 4 | #757575 5 | #33B5E5 6 | #272734 7 | -------------------------------------------------------------------------------- /demo/app/App_Resources/Android/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | 21 | 22 | 23 | 31 | 32 | 34 | 35 | 36 | 42 | 43 | 45 | 46 | -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "icon-29.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "icon-29@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon-29@3x.png", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "icon-40@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon-40@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "57x57", 35 | "idiom" : "iphone", 36 | "filename" : "icon-57.png", 37 | "scale" : "1x" 38 | }, 39 | { 40 | "size" : "57x57", 41 | "idiom" : "iphone", 42 | "filename" : "icon-57@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "icon-60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "icon-60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "29x29", 59 | "idiom" : "ipad", 60 | "filename" : "icon-29.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "icon-29@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "40x40", 71 | "idiom" : "ipad", 72 | "filename" : "icon-40.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "icon-40@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "50x50", 83 | "idiom" : "ipad", 84 | "filename" : "icon-50.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "50x50", 89 | "idiom" : "ipad", 90 | "filename" : "icon-50@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "72x72", 95 | "idiom" : "ipad", 96 | "filename" : "icon-72.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "72x72", 101 | "idiom" : "ipad", 102 | "filename" : "icon-72@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "76x76", 107 | "idiom" : "ipad", 108 | "filename" : "icon-76.png", 109 | "scale" : "1x" 110 | }, 111 | { 112 | "size" : "76x76", 113 | "idiom" : "ipad", 114 | "filename" : "icon-76@2x.png", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "size" : "83.5x83.5", 119 | "idiom" : "ipad", 120 | "filename" : "icon-83.5@2x.png", 121 | "scale" : "2x" 122 | } 123 | ], 124 | "info" : { 125 | "version" : 1, 126 | "author" : "xcode" 127 | } 128 | } -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "Default-736h@3x.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "736h", 16 | "filename" : "Default-Landscape@3x.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "landscape", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "extent" : "full-screen", 23 | "idiom" : "iphone", 24 | "subtype" : "667h", 25 | "filename" : "Default-667h@2x.png", 26 | "minimum-system-version" : "8.0", 27 | "orientation" : "portrait", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "orientation" : "portrait", 32 | "idiom" : "iphone", 33 | "filename" : "Default@2x.png", 34 | "extent" : "full-screen", 35 | "minimum-system-version" : "7.0", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "extent" : "full-screen", 40 | "idiom" : "iphone", 41 | "subtype" : "retina4", 42 | "filename" : "Default-568h@2x.png", 43 | "minimum-system-version" : "7.0", 44 | "orientation" : "portrait", 45 | "scale" : "2x" 46 | }, 47 | { 48 | "orientation" : "portrait", 49 | "idiom" : "ipad", 50 | "filename" : "Default-Portrait.png", 51 | "extent" : "full-screen", 52 | "minimum-system-version" : "7.0", 53 | "scale" : "1x" 54 | }, 55 | { 56 | "orientation" : "landscape", 57 | "idiom" : "ipad", 58 | "filename" : "Default-Landscape.png", 59 | "extent" : "full-screen", 60 | "minimum-system-version" : "7.0", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "orientation" : "portrait", 65 | "idiom" : "ipad", 66 | "filename" : "Default-Portrait@2x.png", 67 | "extent" : "full-screen", 68 | "minimum-system-version" : "7.0", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "orientation" : "landscape", 73 | "idiom" : "ipad", 74 | "filename" : "Default-Landscape@2x.png", 75 | "extent" : "full-screen", 76 | "minimum-system-version" : "7.0", 77 | "scale" : "2x" 78 | }, 79 | { 80 | "orientation" : "portrait", 81 | "idiom" : "iphone", 82 | "filename" : "Default.png", 83 | "extent" : "full-screen", 84 | "scale" : "1x" 85 | }, 86 | { 87 | "orientation" : "portrait", 88 | "idiom" : "iphone", 89 | "filename" : "Default@2x.png", 90 | "extent" : "full-screen", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "orientation" : "portrait", 95 | "idiom" : "iphone", 96 | "filename" : "Default-568h@2x.png", 97 | "extent" : "full-screen", 98 | "subtype" : "retina4", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "orientation" : "portrait", 103 | "idiom" : "ipad", 104 | "extent" : "to-status-bar", 105 | "scale" : "1x" 106 | }, 107 | { 108 | "orientation" : "portrait", 109 | "idiom" : "ipad", 110 | "filename" : "Default-Portrait.png", 111 | "extent" : "full-screen", 112 | "scale" : "1x" 113 | }, 114 | { 115 | "orientation" : "landscape", 116 | "idiom" : "ipad", 117 | "extent" : "to-status-bar", 118 | "scale" : "1x" 119 | }, 120 | { 121 | "orientation" : "landscape", 122 | "idiom" : "ipad", 123 | "filename" : "Default-Landscape.png", 124 | "extent" : "full-screen", 125 | "scale" : "1x" 126 | }, 127 | { 128 | "orientation" : "portrait", 129 | "idiom" : "ipad", 130 | "extent" : "to-status-bar", 131 | "scale" : "2x" 132 | }, 133 | { 134 | "orientation" : "portrait", 135 | "idiom" : "ipad", 136 | "filename" : "Default-Portrait@2x.png", 137 | "extent" : "full-screen", 138 | "scale" : "2x" 139 | }, 140 | { 141 | "orientation" : "landscape", 142 | "idiom" : "ipad", 143 | "extent" : "to-status-bar", 144 | "scale" : "2x" 145 | }, 146 | { 147 | "orientation" : "landscape", 148 | "idiom" : "ipad", 149 | "filename" : "Default-Landscape@2x.png", 150 | "extent" : "full-screen", 151 | "scale" : "2x" 152 | } 153 | ], 154 | "info" : { 155 | "version" : 1, 156 | "author" : "xcode" 157 | } 158 | } -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchScreen-AspectFill.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchScreen-AspectFill@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchScreen-Center.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchScreen-Center@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.1.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiresFullScreen 28 | 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 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 | -------------------------------------------------------------------------------- /demo/app/App_Resources/iOS/build.xcconfig: -------------------------------------------------------------------------------- 1 | // You can add custom settings here 2 | // for example you can uncomment the following line to force distribution code signing 3 | // CODE_SIGN_IDENTITY = iPhone Distribution 4 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 5 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 6 | -------------------------------------------------------------------------------- /demo/app/app.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | import './bundle-config' 3 | /* tslint:enable */ 4 | 5 | import { AlertTypesConstants, StoreUpdate } from 'nativescript-store-update' 6 | import * as application from 'tns-core-modules/application' 7 | 8 | StoreUpdate.init({ 9 | majorUpdateAlertType: AlertTypesConstants.OPTION, 10 | notifyNbDaysAfterRelease: 0, 11 | alertOptions: { 12 | title: 'Attention please', 13 | message: 'Your app is out of date', 14 | }, 15 | }) 16 | 17 | application.start({ moduleName: 'main-page' }) 18 | -------------------------------------------------------------------------------- /demo/app/bundle-config.ts: -------------------------------------------------------------------------------- 1 | if ((global as any).TNS_WEBPACK) { 2 | require('tns-core-modules/bundle-entry-points') 3 | 4 | global.registerModule('main-page', () => require('./main-page')) 5 | } 6 | -------------------------------------------------------------------------------- /demo/app/main-page.ts: -------------------------------------------------------------------------------- 1 | import * as observable from 'tns-core-modules/data/observable' 2 | import * as pages from 'tns-core-modules/ui/page' 3 | import { HelloWorldModel } from './main-view-model' 4 | 5 | // Event handler for Page 'loaded' event attached in main-page.xml 6 | export function pageLoaded(args: observable.EventData) { 7 | // Get the event sender 8 | const page = args.object as pages.Page 9 | page.bindingContext = new HelloWorldModel() 10 | } 11 | -------------------------------------------------------------------------------- /demo/app/main-page.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /demo/app/main-view-model.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'tns-core-modules/data/observable' 2 | 3 | export class HelloWorldModel extends Observable { 4 | constructor() { 5 | super() 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /demo/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tns-template-hello-world-ts", 3 | "main": "app.js", 4 | "version": "1.6.0", 5 | "author": { 6 | "name": "Telerik", 7 | "email": "support@telerik.com" 8 | }, 9 | "description": "Nativescript hello-world-ts project template", 10 | "license": "Apache-2.0", 11 | "keywords": ["telerik", "mobile", "nativescript", "{N}", "tns", "appbuilder", "template"], 12 | "repository": { 13 | "type": "git", 14 | "url": "git+ssh://git@github.com/NativeScript/template-hello-world-ts.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/NativeScript/template-hello-world-ts/issues" 18 | }, 19 | "homepage": "https://github.com/NativeScript/template-hello-world-ts", 20 | "android": { 21 | "v8Flags": "--expose_gc" 22 | }, 23 | "devDependencies": { 24 | "nativescript-dev-typescript": "^0.3.0" 25 | }, 26 | "_id": "tns-template-hello-world-ts@1.6.0", 27 | "_shasum": "a567c2b9a56024818c06596dab9629d155c5b8a8", 28 | "_resolved": "https://registry.npmjs.org/tns-template-hello-world-ts/-/tns-template-hello-world-ts-1.6.0.tgz", 29 | "_from": "tns-template-hello-world-ts@latest", 30 | "scripts": { 31 | "build.plugin": "cd ../src && npm run build", 32 | "ci.tslint": "npm i && tslint --config '../tslint.json' 'app/**/*.ts' --exclude '**/node_modules/**'" 33 | }, 34 | "_npmVersion": "2.14.7", 35 | "_nodeVersion": "4.2.2", 36 | "_npmUser": { 37 | "name": "enchev", 38 | "email": "vladimir.enchev@gmail.com" 39 | }, 40 | "dist": { 41 | "shasum": "a567c2b9a56024818c06596dab9629d155c5b8a8", 42 | "tarball": "http://registry.npmjs.org/tns-template-hello-world-ts/-/tns-template-hello-world-ts-1.6.0.tgz" 43 | }, 44 | "maintainers": [ 45 | { 46 | "name": "enchev", 47 | "email": "vladimir.enchev@gmail.com" 48 | }, 49 | { 50 | "name": "erjangavalji", 51 | "email": "erjan.gavalji@gmail.com" 52 | }, 53 | { 54 | "name": "fatme", 55 | "email": "hfatme@gmail.com" 56 | }, 57 | { 58 | "name": "hdeshev", 59 | "email": "hristo@deshev.com" 60 | }, 61 | { 62 | "name": "kerezov", 63 | "email": "d.kerezov@gmail.com" 64 | }, 65 | { 66 | "name": "ligaz", 67 | "email": "stefan.dobrev@gmail.com" 68 | }, 69 | { 70 | "name": "nsndeck", 71 | "email": "nedyalko.nikolov@telerik.com" 72 | }, 73 | { 74 | "name": "rosen-vladimirov", 75 | "email": "rosen.vladimirov.91@gmail.com" 76 | }, 77 | { 78 | "name": "sdobrev", 79 | "email": "stefan.dobrev@gmail.com" 80 | }, 81 | { 82 | "name": "tailsu", 83 | "email": "tailsu@gmail.com" 84 | }, 85 | { 86 | "name": "teobugslayer", 87 | "email": "teobugslayer@gmail.com" 88 | }, 89 | { 90 | "name": "valio.stoychev", 91 | "email": "valio.stoychev@gmail.com" 92 | } 93 | ], 94 | "_npmOperationalInternal": { 95 | "host": "packages-5-east.internal.npmjs.com", 96 | "tmp": "tmp/tns-template-hello-world-ts-1.6.0.tgz_1455717516189_0.6427943941671401" 97 | }, 98 | "directories": {}, 99 | "readme": "ERROR: No README data found!" 100 | } 101 | -------------------------------------------------------------------------------- /demo/app/tests/app-store.helper.spec.js: -------------------------------------------------------------------------------- 1 | const StoreUpdate = require('nativescript-store-update') 2 | const AppStoreHelper = StoreUpdate.AppStoreHelper 3 | const testConstants = require('./tests.constants.spec') 4 | 5 | describe('AppStoreHelper ', () => { 6 | describe('_getItunesLookupUrl function', () => { 7 | it('returns proper Url', () => { 8 | expect( 9 | AppStoreHelper._getItunesLookupUrl( 10 | testConstants.environment.appId, 11 | testConstants.environment.countryCode 12 | ) 13 | ).toEqual(testConstants.ios.urlWithCountryCode) 14 | }) 15 | 16 | it('returns url without country code if not provided', () => { 17 | expect(AppStoreHelper._getItunesLookupUrl(testConstants.environment.appId)).toEqual( 18 | testConstants.ios.urlWithoutCountryCode 19 | ) 20 | }) 21 | }) 22 | 23 | describe('_parseResource function', () => { 24 | it('returns first available resource', () => { 25 | expect(AppStoreHelper._parseResource(testConstants.ios.validResource)).toEqual( 26 | testConstants.ios.validResource.results[0] 27 | ) 28 | }) 29 | 30 | it('returns null if result count = 0', () => { 31 | expect(AppStoreHelper._parseResource(testConstants.ios.nonValidResource)).toBe(null) 32 | }) 33 | }) 34 | 35 | describe('_getLookupFile function', () => { 36 | it('return fetch with itunesStore lookup url', () => { 37 | const returnValue = 'Success' 38 | spyOn(global, 'fetch').and.returnValue(returnValue) 39 | expect( 40 | AppStoreHelper._getLookupFile( 41 | testConstants.environment.appId, 42 | testConstants.environment.countryCode 43 | ) 44 | ).toEqual(returnValue) 45 | expect(global.fetch).toHaveBeenCalledWith(testConstants.ios.urlWithCountryCode) 46 | }) 47 | }) 48 | 49 | describe('getAppInfos function', () => { 50 | it('returns first result', () => { 51 | const response = { 52 | status: 200, 53 | json: () => testConstants.ios.validResource, 54 | } 55 | const returnValue = testConstants.ios.validResource.results[0] 56 | spyOn(global, 'fetch').and.returnValue(Promise.resolve(response)) 57 | AppStoreHelper.getAppInfos( 58 | testConstants.environment.appId, 59 | testConstants.environment.countryCode 60 | ).then(result => { 61 | expect(result).toEqual(returnValue) 62 | }) 63 | }) 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /demo/app/tests/google-play.helper.spec.js: -------------------------------------------------------------------------------- 1 | const StoreUpdate = require('nativescript-store-update') 2 | const GooglePlayHelper = StoreUpdate.GooglePlayHelper 3 | const testConstants = require('./tests.constants.spec') 4 | 5 | describe('GooglePlayHelper ', () => { 6 | describe('_getStoreAppUrl function', () => { 7 | it('returns proper Url', () => { 8 | expect( 9 | GooglePlayHelper._getStoreAppUrl( 10 | testConstants.environment.appId, 11 | testConstants.environment.countryCode 12 | ) 13 | ).toEqual(testConstants.android.urlWithCountryCode) 14 | }) 15 | 16 | it('returns url without country code if not provided', () => { 17 | expect(GooglePlayHelper._getStoreAppUrl(testConstants.environment.appId)).toEqual( 18 | testConstants.android.urlWithoutCountryCode 19 | ) 20 | }) 21 | }) 22 | 23 | describe('_parseResource function', () => { 24 | it('returns parsed resource', () => { 25 | expect(GooglePlayHelper._parseResource(testConstants.android.storePage)).toEqual( 26 | testConstants.android.storeParsedPage 27 | ) 28 | }) 29 | }) 30 | 31 | describe('_getAppPage function', () => { 32 | it('return fetch with Google play lookup url', () => { 33 | const returnValue = 'Success' 34 | spyOn(global, 'fetch').and.returnValue(returnValue) 35 | expect( 36 | GooglePlayHelper._getAppPage( 37 | testConstants.environment.appId, 38 | testConstants.environment.countryCode 39 | ) 40 | ).toEqual(returnValue) 41 | expect(global.fetch).toHaveBeenCalledWith(testConstants.android.urlWithCountryCode) 42 | }) 43 | }) 44 | 45 | describe('getAppInfos function', () => { 46 | it('TOFIX - returns first result', () => { 47 | const response = { 48 | status: 200, 49 | text: () => testConstants.android.storePage, 50 | } 51 | spyOn(global, 'fetch').and.returnValue(Promise.resolve(response)) 52 | GooglePlayHelper.getAppInfos( 53 | testConstants.environment.appId, 54 | testConstants.environment.countryCode 55 | ).then(result => { 56 | expect(result).toEqual(testConstants.android.storeParsedPage) 57 | }) 58 | }) 59 | }) 60 | }) 61 | -------------------------------------------------------------------------------- /demo/app/tests/locales.helper.sepc.js: -------------------------------------------------------------------------------- 1 | const StoreUpdate = require('nativescript-store-update') 2 | const LocalesHelper = StoreUpdate.LocalesHelper 3 | const testConstants = require('./tests.constants.spec') 4 | 5 | describe('LocalesHelper ', () => { 6 | describe('translate function', () => { 7 | it('returns a translation if it exists', () => { 8 | expect(LocalesHelper.translate(testConstants.translation.key)).toEqual( 9 | testConstants.translation.value 10 | ) 11 | }) 12 | 13 | it('returns a translation if it exists', () => { 14 | expect(LocalesHelper.translate('NOPE')).toEqual('') 15 | }) 16 | }) 17 | 18 | describe('changeLang function', () => { 19 | it(`changes active lang if it's available`, () => { 20 | expect(LocalesHelper.currentLang).toEqual('en') 21 | LocalesHelper.changeLang('fr') 22 | expect(LocalesHelper.currentLang).toEqual('fr') 23 | }) 24 | 25 | it(`changes use non regionalized version if it necessary`, () => { 26 | LocalesHelper.changeLang('en') 27 | expect(LocalesHelper.currentLang).toEqual('en') 28 | LocalesHelper.changeLang('fr-NOPE') 29 | expect(LocalesHelper.currentLang).toEqual('fr') 30 | }) 31 | 32 | it(`does not change active lang if translation is not available`, () => { 33 | LocalesHelper.changeLang('en') 34 | expect(LocalesHelper.currentLang).toEqual('en') 35 | LocalesHelper.changeLang('nope') 36 | expect(LocalesHelper.currentLang).toEqual('en') 37 | }) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /demo/app/tests/response.helper.spec.js: -------------------------------------------------------------------------------- 1 | const StoreUpdate = require('nativescript-store-update') 2 | const ResponseHelper = StoreUpdate.ResponseHelper 3 | const testConstants = require('./tests.constants.spec') 4 | 5 | describe('ResponseHelper ', () => { 6 | describe('handleErrorStatus function', () => { 7 | it('returns response if status is ok', () => { 8 | expect(ResponseHelper.handleErrorStatus(testConstants.HTTPResponse.success)).toEqual( 9 | testConstants.HTTPResponse.success 10 | ) 11 | }) 12 | 13 | it('raises an error if status is an error', () => { 14 | expect(() => ResponseHelper.handleErrorStatus(testConstants.HTTPResponse.error)).toThrow() 15 | }) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /demo/app/tests/store-update-android.spec.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment') 2 | const StoreUpdateModule = require('nativescript-store-update') 3 | const platform = require('tns-core-modules/platform') 4 | const utils = require('tns-core-modules/utils/utils') 5 | const StoreUpdate = StoreUpdateModule.StoreUpdate 6 | const AlertTypesConstants = StoreUpdateModule.AlertTypesConstants 7 | const testConstants = require('./tests.constants.spec') 8 | 9 | if (!platform.isAndroid) return 10 | 11 | describe('StoreUpdate ANDROID ', () => { 12 | beforeAll(() => { 13 | try { 14 | StoreUpdate.init(testConstants.config) 15 | } catch (err) { 16 | console.log(`StoreUpdate already init in another test`) 17 | } 18 | }) 19 | 20 | it(`can't be init more than once`, () => { 21 | const newConf = Object.assign({}, testConstants.config, { 22 | countryCode: 'fr', 23 | }) 24 | const secondInit = () => StoreUpdate.init(newConf) 25 | expect(secondInit).toThrow() 26 | }) 27 | 28 | describe('_extendResults function', () => { 29 | it('returns formated results', () => { 30 | const results = { 31 | version: testConstants.environment.appVersion, 32 | os: testConstants.environment.osVersion, 33 | date: testConstants.dates.today, 34 | } 35 | const extendedResults = { 36 | currentVersionReleaseDate: results.date, 37 | minimumOsVersion: results.os, 38 | systemVersion: android.os.Build.VERSION.RELEASE, 39 | version: results.version, 40 | } 41 | expect(StoreUpdate._extendResults(results)).toEqual(extendedResults) 42 | }) 43 | }) 44 | 45 | describe('_openStore function', () => { 46 | it('opens store page', () => { 47 | spyOn(utils, 'openUrl') 48 | StoreUpdate._openStore() 49 | expect(utils.openUrl).toHaveBeenCalledWith(testConstants.android.storeURL) 50 | }) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /demo/app/tests/store-update-common.spec.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment') 2 | const StoreUpdateModule = require('nativescript-store-update') 3 | const appSettings = require('tns-core-modules/application-settings') 4 | const dialogs = require('tns-core-modules/ui/dialogs') 5 | const platform = require('tns-core-modules/platform') 6 | const StoreUpdate = StoreUpdateModule.StoreUpdate 7 | const UpdateTypesConstants = StoreUpdateModule.UpdateTypesConstants 8 | const AlertTypesConstants = StoreUpdateModule.AlertTypesConstants 9 | const testConstants = require('./tests.constants.spec') 10 | 11 | let storeUpdateCommon 12 | 13 | describe('StoreUpdateCommon ', () => { 14 | 15 | beforeAll(() => { 16 | StoreUpdate.init(testConstants.config) 17 | storeUpdateCommon = StoreUpdate._common 18 | }) 19 | 20 | describe('init function', () => { 21 | 22 | it('sets _majorUpdateAlertType to config', () => { 23 | expect(storeUpdateCommon._majorUpdateAlertType).toEqual(testConstants.config.majorUpdateAlertType) 24 | }) 25 | 26 | it('sets _minorUpdateAlertType to config', () => { 27 | expect(storeUpdateCommon._minorUpdateAlertType).toEqual(testConstants.config.minorUpdateAlertType) 28 | }) 29 | 30 | it('sets _patchUpdateAlertType to config', () => { 31 | expect(storeUpdateCommon._patchUpdateAlertType).toEqual(testConstants.config.patchUpdateAlertType) 32 | }) 33 | 34 | it('sets _revisionUpdateAlertType to config', () => { 35 | expect(storeUpdateCommon._revisionUpdateAlertType).toEqual( 36 | testConstants.config.revisionUpdateAlertType 37 | ) 38 | }) 39 | 40 | it('sets _notifyNbDaysAfterRelease to config', () => { 41 | expect(storeUpdateCommon._notifyNbDaysAfterRelease).toEqual( 42 | testConstants.config.notifyNbDaysAfterRelease 43 | ) 44 | }) 45 | 46 | it('sets _countryCode to config', () => { 47 | expect(storeUpdateCommon.countryCode).toEqual(testConstants.config.countryCode) 48 | }) 49 | }) 50 | 51 | describe('getBundleId function', () => { 52 | it('returns appId', () => { 53 | expect(storeUpdateCommon.getBundleId()).toEqual(testConstants.environment.appId) 54 | }) 55 | }) 56 | 57 | describe('getLocalVersionNumber function', () => { 58 | it('returns app version', () => { 59 | expect(storeUpdateCommon.getLocalVersionNumber()).toEqual(testConstants.environment.appVersion) 60 | }) 61 | }) 62 | 63 | describe('isEligibleForUpdate function', () => { 64 | beforeAll(() => { 65 | appSettings.setString('lastVersionSkipped', testConstants.updates.patch) 66 | }) 67 | it('returns true if new version released for long enough matching OS min versions', () => { 68 | expect( 69 | storeUpdateCommon.isEligibleForUpdate({ 70 | version: testConstants.updates.major, 71 | currentVersionReleaseDate: testConstants.dates.threeDaysAgo, 72 | minimumOsVersion: testConstants.environment.osVersion, 73 | systemVersion: testConstants.environment.osVersion, 74 | }) 75 | ).toBe(true) 76 | }) 77 | it('returns false if store version is older than local', () => { 78 | expect( 79 | storeUpdateCommon.isEligibleForUpdate({ 80 | version: testConstants.updates.past, 81 | currentVersionReleaseDate: testConstants.dates.threeDaysAgo, 82 | minimumOsVersion: testConstants.environment.osVersion, 83 | systemVersion: testConstants.environment.osVersion, 84 | }) 85 | ).toBe(false) 86 | }) 87 | it('returns false if store version is equal to local', () => { 88 | expect( 89 | storeUpdateCommon.isEligibleForUpdate({ 90 | version: testConstants.environment.appVersion, 91 | currentVersionReleaseDate: testConstants.dates.threeDaysAgo, 92 | minimumOsVersion: testConstants.environment.osVersion, 93 | systemVersion: testConstants.environment.osVersion, 94 | }) 95 | ).toBe(false) 96 | }) 97 | it('returns false if release date is too close', () => { 98 | expect( 99 | storeUpdateCommon.isEligibleForUpdate({ 100 | version: testConstants.updates.major, 101 | currentVersionReleaseDate: testConstants.dates.today, 102 | minimumOsVersion: testConstants.environment.osVersion, 103 | systemVersion: testConstants.environment.osVersion, 104 | }) 105 | ).toBe(false) 106 | }) 107 | it('returns false if os version is under min version required', () => { 108 | expect( 109 | storeUpdateCommon.isEligibleForUpdate({ 110 | version: testConstants.updates.major, 111 | currentVersionReleaseDate: testConstants.dates.threeDaysAgo, 112 | minimumOsVersion: testConstants.environment.osVersion, 113 | systemVersion: testConstants.os.lower, 114 | }) 115 | ).toBe(false) 116 | }) 117 | it('returns false if app version was skipped', () => { 118 | expect( 119 | storeUpdateCommon.isEligibleForUpdate({ 120 | version: testConstants.updates.patch, 121 | currentVersionReleaseDate: testConstants.dates.threeDaysAgo, 122 | minimumOsVersion: testConstants.environment.osVersion, 123 | systemVersion: testConstants.environment.osVersion, 124 | }) 125 | ).toBe(false) 126 | }) 127 | afterAll(() => { 128 | appSettings.remove('lastVersionSkipped') 129 | }) 130 | }) 131 | 132 | describe('setVersionAsSkipped function', () => { 133 | beforeAll(() => { 134 | spyOn(appSettings, 'setString') 135 | }) 136 | it('sets skipped version in app settings', () => { 137 | const version = testConstants.updates.minor 138 | storeUpdateCommon.setVersionAsSkipped(version) 139 | expect(appSettings.setString).toHaveBeenCalledWith('lastVersionSkipped', version) 140 | }) 141 | }) 142 | 143 | describe('triggerAlertForUpdate function', () => { 144 | beforeAll(() => { 145 | spyOn(storeUpdateCommon, '_onConfirmed') 146 | spyOn(storeUpdateCommon, 'setVersionAsSkipped') 147 | }) 148 | it('opens store if confirmed', () => { 149 | spyOn(dialogs, 'confirm').and.returnValue(Promise.resolve(true)) 150 | storeUpdateCommon.triggerAlertForUpdate(testConstants.updates.minor).then(() => { 151 | expect(storeUpdateCommon._onConfirmed).toHaveBeenCalled() 152 | }) 153 | }) 154 | it('skips version if not confirmed', () => { 155 | spyOn(dialogs, 'confirm').and.returnValue(Promise.resolve(false)) 156 | storeUpdateCommon.triggerAlertForUpdate(testConstants.updates.minor).then(() => { 157 | expect(storeUpdateCommon.setVersionAsSkipped).toHaveBeenCalled() 158 | }) 159 | }) 160 | }) 161 | 162 | describe('getAlertTypeForVersion function', () => { 163 | it('returns config majorUpdateAlertType for major update', () => { 164 | expect(storeUpdateCommon.getAlertTypeForVersion(testConstants.updates.major)).toEqual( 165 | testConstants.config.majorUpdateAlertType 166 | ) 167 | }) 168 | it('returns config minorUpdateAlertType for minor update', () => { 169 | expect(storeUpdateCommon.getAlertTypeForVersion(testConstants.updates.minor)).toEqual( 170 | testConstants.config.minorUpdateAlertType 171 | ) 172 | }) 173 | it('returns config patchUpdateAlertType for patch update', () => { 174 | expect(storeUpdateCommon.getAlertTypeForVersion(testConstants.updates.patch)).toEqual( 175 | testConstants.config.patchUpdateAlertType 176 | ) 177 | }) 178 | it('returns config revisionUpdateAlertType for revision update', () => { 179 | expect(storeUpdateCommon.getAlertTypeForVersion(testConstants.updates.revision)).toEqual( 180 | testConstants.config.revisionUpdateAlertType 181 | ) 182 | }) 183 | }) 184 | 185 | describe('buildDialogOptions function', () => { 186 | it('returns options with neutralButtonText by default', () => { 187 | expect(storeUpdateCommon.buildDialogOptions()).toEqual(testConstants.alerts.skippableOptions) 188 | }) 189 | it('returns options with neutralButtonText if skippable is true', () => { 190 | expect(storeUpdateCommon.buildDialogOptions({ skippable: true })).toEqual( 191 | testConstants.alerts.skippableOptions 192 | ) 193 | }) 194 | it('returns options without neutralButtonText if skippable is false', () => { 195 | expect(storeUpdateCommon.buildDialogOptions({ skippable: false })).toEqual( 196 | testConstants.alerts.defaultOptions 197 | ) 198 | }) 199 | }) 200 | 201 | describe('showAbuildDialogOptionslertForUpdate function', () => { 202 | beforeAll(() => { 203 | spyOn(dialogs, 'confirm').and.returnValue(Promise.resolve()) 204 | }) 205 | it('displays config majorUpdateAlertType confirm for major update', () => { 206 | const skippable = testConstants.config.majorUpdateAlertType !== AlertTypesConstants.FORCE 207 | const expectedOptions = storeUpdateCommon.buildDialogOptions({ skippable }) 208 | storeUpdateCommon.showAlertForUpdate(testConstants.updates.major) 209 | expect(dialogs.confirm).toHaveBeenCalledWith(expectedOptions) 210 | }) 211 | it('displays config minorUpdateAlertType confirm for minor update', () => { 212 | const skippable = testConstants.config.minorUpdateAlertType !== AlertTypesConstants.FORCE 213 | const expectedOptions = storeUpdateCommon.buildDialogOptions({ skippable }) 214 | storeUpdateCommon.showAlertForUpdate(testConstants.updates.minor) 215 | expect(dialogs.confirm).toHaveBeenCalledWith(expectedOptions) 216 | }) 217 | it('does not display confirm for config PatchUpdate version', () => { 218 | storeUpdateCommon.showAlertForUpdate(testConstants.updates.patch).catch(err => 219 | expect(err).toEqual(null) 220 | ) 221 | }) 222 | it('displays config revisionUpdateAlertType confirm for minor update', () => { 223 | const skippable = testConstants.config.revisionUpdateAlertType !== AlertTypesConstants.FORCE 224 | const expectedOptions = storeUpdateCommon.buildDialogOptions({ skippable }) 225 | storeUpdateCommon.showAlertForUpdate(testConstants.updates.revision) 226 | expect(dialogs.confirm).toHaveBeenCalledWith(expectedOptions) 227 | }) 228 | }) 229 | 230 | describe('_getUpdateTypeForVersion function', () => { 231 | it('returns MAJOR code if major update', () => { 232 | expect(storeUpdateCommon._getUpdateTypeForVersion(testConstants.updates.major)).toEqual( 233 | UpdateTypesConstants.MAJOR 234 | ) 235 | }) 236 | 237 | it('returns MINOR code if minor update', () => { 238 | expect(storeUpdateCommon._getUpdateTypeForVersion(testConstants.updates.minor)).toEqual( 239 | UpdateTypesConstants.MINOR 240 | ) 241 | }) 242 | 243 | it('returns PATCH code if patch update', () => { 244 | expect(storeUpdateCommon._getUpdateTypeForVersion(testConstants.updates.patch)).toEqual( 245 | UpdateTypesConstants.PATCH 246 | ) 247 | }) 248 | 249 | it('returns REVISION code if revision update', () => { 250 | expect(storeUpdateCommon._getUpdateTypeForVersion(testConstants.updates.revision)).toEqual( 251 | UpdateTypesConstants.REVISION 252 | ) 253 | }) 254 | 255 | it('returns -1 code if no update', () => { 256 | expect(storeUpdateCommon._getUpdateTypeForVersion(testConstants.environment.appVersion)).toEqual(-1) 257 | }) 258 | }) 259 | 260 | describe('_isUpdateCompatibleWithDeviceOS function', () => { 261 | it('returns true if minimum required version is null', () => { 262 | expect( 263 | storeUpdateCommon._isUpdateCompatibleWithDeviceOS(testConstants.environment.osVersion, null) 264 | ).toBe(true) 265 | }) 266 | 267 | it('returns true if os version is higher than minimum required version', () => { 268 | expect( 269 | storeUpdateCommon._isUpdateCompatibleWithDeviceOS( 270 | testConstants.environment.osVersion, 271 | testConstants.os.lower 272 | ) 273 | ).toBe(true) 274 | }) 275 | 276 | it('returns true if os version is equal to minimum required version', () => { 277 | expect( 278 | storeUpdateCommon._isUpdateCompatibleWithDeviceOS( 279 | testConstants.environment.osVersion, 280 | testConstants.environment.osVersion 281 | ) 282 | ).toBe(true) 283 | }) 284 | 285 | it('returns false if os version is lower than minimum required version', () => { 286 | expect( 287 | storeUpdateCommon._isUpdateCompatibleWithDeviceOS( 288 | testConstants.environment.osVersion, 289 | testConstants.os.higher 290 | ) 291 | ).toBe(false) 292 | }) 293 | }) 294 | 295 | describe('_hasBeenReleasedLongerThanDelay function', () => { 296 | it('returns true if release delay is superior to config', () => { 297 | expect( 298 | storeUpdateCommon._hasBeenReleasedLongerThanDelay(testConstants.dates.threeDaysAgo.toDate()) 299 | ).toBe(true) 300 | }) 301 | 302 | it('returns false if release delay is inferior to config', () => { 303 | expect(storeUpdateCommon._hasBeenReleasedLongerThanDelay(testConstants.dates.today.toDate())).toBe( 304 | false 305 | ) 306 | }) 307 | 308 | it('returns false if no release date is given', () => { 309 | expect(storeUpdateCommon._hasBeenReleasedLongerThanDelay()).toBe(false) 310 | }) 311 | }) 312 | 313 | describe('triggerAlertIfEligible function', () => { 314 | const results = { 315 | bundleId: testConstants.environment.appId, 316 | trackId: 12, 317 | version: testConstants.updates.major, 318 | minimumOsVersion: testConstants.os.lower, 319 | currentVersionReleaseDate: testConstants.dates.threeDaysAgo.toDate(), 320 | systemVersion: testConstants.environment.osVersion, 321 | } 322 | 323 | it('calls triggerAlertForUpdate if new valid version is available', () => { 324 | spyOn(storeUpdateCommon, 'triggerAlertForUpdate') 325 | storeUpdateCommon.triggerAlertIfEligible(results) 326 | expect(storeUpdateCommon.triggerAlertForUpdate).toHaveBeenCalled() 327 | }) 328 | 329 | it('does not call triggerAlertForUpdate if no new valid version is available', () => { 330 | const invalidResults = Object.assign(results, { 331 | version: testConstants.updates.past, 332 | }) 333 | spyOn(storeUpdateCommon, 'triggerAlertForUpdate') 334 | storeUpdateCommon.triggerAlertIfEligible(results) 335 | expect(storeUpdateCommon.triggerAlertForUpdate).not.toHaveBeenCalled() 336 | }) 337 | }) 338 | 339 | describe('_isAppStoreVersionNewer function', () => { 340 | it('returns true if store version is superior to local', () => { 341 | expect(storeUpdateCommon._isAppStoreVersionNewer(testConstants.updates.major)).toBe(true) 342 | }) 343 | 344 | it('returns false if store version is equal to local', () => { 345 | expect(storeUpdateCommon._isAppStoreVersionNewer(testConstants.environment.appVersion)).toBe(false) 346 | }) 347 | 348 | it('returns false if store version is inferior to local', () => { 349 | expect(storeUpdateCommon._isAppStoreVersionNewer(testConstants.updates.past)).toBe(false) 350 | }) 351 | }) 352 | 353 | describe('_isCurrentVersionSkipped function', () => { 354 | beforeAll(() => { 355 | appSettings.remove('lastVersionSkipped') 356 | }) 357 | 358 | it('returns false if store version is not defined', () => { 359 | expect(storeUpdateCommon._isCurrentVersionSkipped(testConstants.updates.major)).toBe(false) 360 | }) 361 | 362 | it('returns true if store version is matching local', () => { 363 | appSettings.setString('lastVersionSkipped', testConstants.updates.major) 364 | expect(storeUpdateCommon._isCurrentVersionSkipped(testConstants.updates.major)).toBe(true) 365 | }) 366 | 367 | it('returns false if store version is not matching local', () => { 368 | expect(storeUpdateCommon._isCurrentVersionSkipped(testConstants.updates.minor)).toBe(false) 369 | }) 370 | 371 | afterAll(() => { 372 | appSettings.remove('lastVersionSkipped') 373 | }) 374 | }) 375 | }) 376 | -------------------------------------------------------------------------------- /demo/app/tests/store-update-ios.spec.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment') 2 | const StoreUpdateModule = require('nativescript-store-update') 3 | const platform = require('tns-core-modules/platform') 4 | const utils = require('tns-core-modules/utils/utils') 5 | const StoreUpdate = StoreUpdateModule.StoreUpdate 6 | const AlertTypesConstants = StoreUpdateModule.AlertTypesConstants 7 | const testConstants = require('./tests.constants.spec') 8 | 9 | if (!platform.isIOS) return 10 | 11 | describe('StoreUpdate IOS ', () => { 12 | beforeAll(() => { 13 | try { 14 | StoreUpdate.init(testConstants.config) 15 | } catch (err) { 16 | console.log(`StoreUpdate already init in another test`) 17 | } 18 | }) 19 | 20 | it(`can't be init more than once`, () => { 21 | const newConf = Object.assign({}, testConstants.config, { 22 | countryCode: 'fr', 23 | }) 24 | const secondInit = () => StoreUpdate.init(newConf) 25 | expect(secondInit).toThrow() 26 | }) 27 | 28 | describe('_openStore function', () => { 29 | it('opens store page', () => { 30 | StoreUpdate._trackViewUrl = testConstants.ios.trackViewUrl 31 | const storeURL = NSURL.URLWithString(testConstants.ios.storeURL).absoluteString 32 | spyOn(utils, 'openUrl') 33 | StoreUpdate._openStore() 34 | expect(utils.openUrl).toHaveBeenCalledWith(storeURL) 35 | }) 36 | }) 37 | 38 | describe('_extendResults function', () => { 39 | it('returns formated results', () => { 40 | const results = { 41 | bundleId: testConstants.environment.appId, 42 | trackId: 12, 43 | version: testConstants.environment.appVersion, 44 | minimumOsVersion: testConstants.environment.osVersion, 45 | currentVersionReleaseDate: testConstants.dates.today.toDate(), 46 | } 47 | const extendedResults = Object.assign( 48 | { 49 | systemVersion: testConstants.environment.osVersion, 50 | }, 51 | results 52 | ) 53 | expect(StoreUpdate._extendResults(results)).toEqual(extendedResults) 54 | }) 55 | }) 56 | }) 57 | -------------------------------------------------------------------------------- /demo/app/tests/tests.constants.spec.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment') 2 | const platform = require('tns-core-modules/platform') 3 | const StoreUpdateModule = require('nativescript-store-update') 4 | const AlertTypesConstants = StoreUpdateModule.AlertTypesConstants 5 | const LocalesHelper = StoreUpdateModule.LocalesHelper 6 | 7 | const environment = { 8 | appId: 'com.bitstrips.imoji', 9 | appVersion: '1.1.1.1', 10 | buildVersion: '123', 11 | countryCode: 'ca', 12 | osVersion: platform.device.osVersion, 13 | } 14 | 15 | const dates = { 16 | today: moment(), 17 | threeDaysAgo: moment().subtract(3, 'days'), 18 | } 19 | 20 | // Alerts 21 | const defaultOptions = { 22 | message: LocalesHelper.translate('ALERT_MESSAGE'), 23 | neutralButtonText: null, 24 | okButtonText: LocalesHelper.translate('ALERT_UPDATE_BUTTON'), 25 | title: LocalesHelper.translate('ALERT_TITLE'), 26 | } 27 | const skippableOptions = Object.assign({}, defaultOptions, { 28 | neutralButtonText: LocalesHelper.translate('ALERT_SKIP_BUTTON'), 29 | }) 30 | const alerts = { defaultOptions, skippableOptions } 31 | 32 | const android = { 33 | urlWithCountryCode: `https://play.google.com/store/apps/details?id=${environment.appId}&hl=${environment.countryCode}`, 34 | urlWithoutCountryCode: `https://play.google.com/store/apps/details?id=${environment.appId}`, 35 | storeURL: `market://details?id=${environment.appId}`, 36 | storePage: ` 37 |
38 |
39 |
${environment.osVersion} and beyond
40 |
${environment.buildVersion}
41 |
42 | `, 43 | storeParsedPage: { 44 | date: dates.threeDaysAgo.format('D MMM YYYY'), 45 | os: environment.osVersion, 46 | version: environment.buildVersion, 47 | }, 48 | } 49 | 50 | const config = { 51 | majorUpdateAlertType: AlertTypesConstants.FORCE, 52 | minorUpdateAlertType: AlertTypesConstants.OPTION, 53 | patchUpdateAlertType: AlertTypesConstants.NONE, 54 | revisionUpdateAlertType: AlertTypesConstants.OPTION, 55 | notifyNbDaysAfterRelease: 2, 56 | countryCode: environment.countryCode, 57 | } 58 | 59 | const HTTPResponse = { 60 | success: { status: 200 }, 61 | error: { status: 404 }, 62 | } 63 | 64 | const ios = { 65 | urlWithCountryCode: `https://itunes.apple.com/lookup?bundleId=${environment.appId}&hl=${environment.countryCode}`, 66 | urlWithoutCountryCode: `https://itunes.apple.com/lookup?bundleId=${environment.appId}`, 67 | trackViewUrl: `https://itunes.apple.com/us/app/bitmoji/id868077558?mt=8&uo=4`, 68 | storeURL: `itms-apps://itunes.apple.com/us/app/bitmoji/id868077558?mt=8&uo=4`, 69 | validResource: { 70 | resultCount: 3, 71 | results: [1, 2, 3], 72 | }, 73 | nonValidResource: { 74 | resultCount: 0, 75 | }, 76 | } 77 | 78 | const translation = { 79 | key: 'ALERT_TITLE', 80 | value: 'Update available', 81 | } 82 | 83 | const updates = { 84 | major: '2.1.1.1', 85 | minor: '1.2.1.1', 86 | patch: '1.1.2.1', 87 | revision: '1.1.1.2', 88 | past: '0.0.0.1', 89 | } 90 | 91 | const os = { 92 | lower: '0.1', 93 | higher: '100.2', 94 | } 95 | 96 | module.exports = { 97 | alerts, 98 | android, 99 | config, 100 | dates, 101 | environment, 102 | HTTPResponse, 103 | ios, 104 | os, 105 | translation, 106 | updates, 107 | } 108 | -------------------------------------------------------------------------------- /demo/app/tests/version.helper.spec.js: -------------------------------------------------------------------------------- 1 | const StoreUpdate = require('nativescript-store-update') 2 | const VersionHelper = StoreUpdate.VersionHelper 3 | 4 | describe('VersionHelper ', () => { 5 | describe('_compareVersions function', () => { 6 | it('returns 1 if a version is > b version', () => { 7 | expect(VersionHelper._compareVersions('2.0.0.0', '1.0.0.0')).toEqual(1) 8 | expect(VersionHelper._compareVersions('1.2.0.0', '1.0.0.0')).toEqual(1) 9 | expect(VersionHelper._compareVersions('1.0.2.0', '1.0.0.0')).toEqual(1) 10 | }) 11 | 12 | it('returns -1 if a version is < b version', () => { 13 | expect(VersionHelper._compareVersions('1.0.0.0', '2.0.0.0')).toEqual(-1) 14 | expect(VersionHelper._compareVersions('1.0.0.0', '1.2.0.0')).toEqual(-1) 15 | expect(VersionHelper._compareVersions('1.0.0.0', '1.0.2.0')).toEqual(-1) 16 | }) 17 | 18 | it('returns 0 if a version is === b version', () => { 19 | expect(VersionHelper._compareVersions('1.0.0.0', '1.0.0.0')).toEqual(0) 20 | }) 21 | }) 22 | 23 | describe('_isIndexSectionHigher function', () => { 24 | it('returns true if version section a is higher than b', () => { 25 | expect(VersionHelper._isIndexSectionHigher('2.0.0.0', '1.0.0.0', 0)).toBe(true) 26 | expect(VersionHelper._isIndexSectionHigher('1.2.0.0', '1.0.0.0', 1)).toBe(true) 27 | expect(VersionHelper._isIndexSectionHigher('1.0.2.0', '1.0.0.0', 2)).toBe(true) 28 | expect(VersionHelper._isIndexSectionHigher('1.0.0.2', '1.0.0.0', 3)).toBe(true) 29 | }) 30 | 31 | it('returns false if version section a is lower than b', () => { 32 | expect(VersionHelper._isIndexSectionHigher('1.0.0.0', '2.0.0.0', 0)).toBe(false) 33 | expect(VersionHelper._isIndexSectionHigher('1.0.0.0', '1.2.0.0', 1)).toBe(false) 34 | expect(VersionHelper._isIndexSectionHigher('1.0.0.0', '1.0.2.0', 2)).toBe(false) 35 | expect(VersionHelper._isIndexSectionHigher('1.0.0.0', '1.0.0.2', 3)).toBe(false) 36 | }) 37 | 38 | it(`returns false if version section doesn't exists on a`, () => { 39 | expect(VersionHelper._isIndexSectionHigher('2', '1.0', 1)).toBe(false) 40 | }) 41 | 42 | it(`returns true if version section doesn't exists on b`, () => { 43 | expect(VersionHelper._isIndexSectionHigher('2.0', '1', 1)).toBe(true) 44 | }) 45 | }) 46 | 47 | describe('isHigher function', () => { 48 | it('returns true if version a is higher than b', () => { 49 | expect(VersionHelper.isHigher('2.0.0.0', '1.0.0.0')).toBe(true) 50 | }) 51 | 52 | it('returns false if version a is equal to b', () => { 53 | expect(VersionHelper.isHigher('2.0.0.0', '2.0.0.0')).toBe(false) 54 | }) 55 | 56 | it('returns false if version a is lower than b', () => { 57 | expect(VersionHelper.isHigher('1.0.0.0', '2.0.0.0')).toBe(false) 58 | }) 59 | }) 60 | 61 | describe('isEqualOrHigher function', () => { 62 | it('returns true if version a is higher than b', () => { 63 | expect(VersionHelper.isEqualOrHigher('2.0.0.0', '1.0.0.0')).toBe(true) 64 | }) 65 | 66 | it('returns true if version a is equal to b', () => { 67 | expect(VersionHelper.isEqualOrHigher('2.0.0.0', '2.0.0.0')).toBe(true) 68 | }) 69 | 70 | it('returns false if version a is lower than b', () => { 71 | expect(VersionHelper.isEqualOrHigher('1.0.0.0', '2.0.0.0')).toBe(false) 72 | }) 73 | }) 74 | 75 | describe('isMajorUpdate function', () => { 76 | it('returns true if major version a is higher than major b', () => { 77 | expect(VersionHelper.isMajorUpdate('2.0.0.0', '1.0.0.0')).toBe(true) 78 | }) 79 | 80 | it('returns false if major version a is equal to major b', () => { 81 | expect(VersionHelper.isMajorUpdate('2.0.0.0', '2.0.0.0')).toBe(false) 82 | }) 83 | 84 | it('returns false if major version a is lower than major b', () => { 85 | expect(VersionHelper.isMajorUpdate('1.0.0.0', '2.0.0.0')).toBe(false) 86 | }) 87 | }) 88 | 89 | describe('isMinorUpdate function', () => { 90 | it('returns true if minor version a is higher than minor b', () => { 91 | expect(VersionHelper.isMinorUpdate('1.2.0.0', '1.0.0.0')).toBe(true) 92 | }) 93 | 94 | it('returns false if minor version a is equal to minor b', () => { 95 | expect(VersionHelper.isMinorUpdate('1.2.0.0', '1.2.0.0')).toBe(false) 96 | }) 97 | 98 | it('returns false if minor version a is lower than minor b', () => { 99 | expect(VersionHelper.isMinorUpdate('1.0.0.0', '1.2.0.0')).toBe(false) 100 | }) 101 | }) 102 | 103 | describe('isPatchUpdate function', () => { 104 | it('returns true if patch version a is higher than patch b', () => { 105 | expect(VersionHelper.isPatchUpdate('1.0.2.0', '1.0.0.0')).toBe(true) 106 | }) 107 | 108 | it('returns false if patch version a is equal to patch b', () => { 109 | expect(VersionHelper.isPatchUpdate('1.0.2.0', '1.0.2.0')).toBe(false) 110 | }) 111 | 112 | it('returns false if patch version a is lower than patch b', () => { 113 | expect(VersionHelper.isPatchUpdate('1.0.0.0', '1.0.2.0')).toBe(false) 114 | }) 115 | }) 116 | 117 | describe('isRevisionUpdate function', () => { 118 | it('returns true if revision version a is higher than revision b', () => { 119 | expect(VersionHelper.isRevisionUpdate('1.0.0.2', '1.0.0.0')).toBe(true) 120 | }) 121 | 122 | it('returns false if revision version a is equal to revision b', () => { 123 | expect(VersionHelper.isRevisionUpdate('1.0.0.2', '1.0.0.2')).toBe(false) 124 | }) 125 | 126 | it('returns false if revision version a is lower than revision b', () => { 127 | expect(VersionHelper.isRevisionUpdate('1.0.0.0', '1.0.0.2')).toBe(false) 128 | }) 129 | }) 130 | }) 131 | -------------------------------------------------------------------------------- /demo/app/vendor-platform.android.ts: -------------------------------------------------------------------------------- 1 | require('application') 2 | /* tslint:disable-next-line: no-string-literal */ 3 | if (!global['__snapshot']) { 4 | /* 5 | In case snapshot generation is enabled these modules will get into the bundle but will not be required/evaluated. 6 | The snapshot webpack plugin will add them to the tns-java-classes.js bundle file. This way, they will be evaluated on app start as early as possible. 7 | */ 8 | require('ui/frame') 9 | require('ui/frame/activity') 10 | } 11 | -------------------------------------------------------------------------------- /demo/app/vendor-platform.ios.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/vendor-platform.ios.ts -------------------------------------------------------------------------------- /demo/app/vendor-platform.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/demo/app/vendor-platform.ts -------------------------------------------------------------------------------- /demo/app/vendor.ts: -------------------------------------------------------------------------------- 1 | require('./vendor-platform') 2 | 3 | require('bundle-entry-points') 4 | -------------------------------------------------------------------------------- /demo/karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | 4 | // base path that will be used to resolve all patterns (eg. files, exclude) 5 | basePath: '', 6 | 7 | 8 | // frameworks to use 9 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 10 | frameworks: ['jasmine'], 11 | 12 | 13 | // list of files / patterns to load in the browser 14 | files: [ 15 | 'app/**/*.js' 16 | ], 17 | 18 | 19 | // list of files to exclude 20 | exclude: [ 21 | ], 22 | 23 | 24 | // preprocess matching files before serving them to the browser 25 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 26 | preprocessors: { 27 | }, 28 | 29 | 30 | // test results reporter to use 31 | // possible values: 'dots', 'progress' 32 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 33 | reporters: ['progress'], 34 | 35 | 36 | // web server port 37 | port: 9876, 38 | 39 | 40 | // enable / disable colors in the output (reporters and logs) 41 | colors: true, 42 | 43 | 44 | // level of logging 45 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 46 | logLevel: config.LOG_INFO, 47 | 48 | 49 | // enable / disable watching file and executing tests whenever any file changes 50 | autoWatch: true, 51 | 52 | 53 | // start these browsers 54 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 55 | browsers: [], 56 | 57 | customLaunchers: { 58 | android: { 59 | base: 'NS', 60 | platform: 'android' 61 | }, 62 | ios: { 63 | base: 'NS', 64 | platform: 'ios' 65 | }, 66 | ios_simulator: { 67 | base: 'NS', 68 | platform: 'ios', 69 | arguments: ['--emulator'] 70 | } 71 | }, 72 | 73 | // Continuous Integration mode 74 | // if true, Karma captures browsers, runs the tests and exits 75 | singleRun: true 76 | }); 77 | }; 78 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "nativescript": { 3 | "id": "com.bitstrips.imoji", 4 | "tns-ios": { 5 | "version": "3.2.0" 6 | }, 7 | "tns-android": { 8 | "version": "3.2.0" 9 | } 10 | }, 11 | "dependencies": { 12 | "moment": "2.18.1", 13 | "nativescript-appversion": "^1.4.1", 14 | "nativescript-store-update": "file:../src", 15 | "nativescript-unit-test-runner": "^0.3.4", 16 | "tns-core-modules": "^3.2.0" 17 | }, 18 | "devDependencies": { 19 | "awesome-typescript-loader": "~3.1.3", 20 | "babel-traverse": "6.12.0", 21 | "babel-types": "6.11.1", 22 | "babylon": "6.8.4", 23 | "copy-webpack-plugin": "~4.0.1", 24 | "extract-text-webpack-plugin": "~3.0.0", 25 | "filewalker": "0.1.2", 26 | "jasmine-core": "^2.5.2", 27 | "karma": "^1.3.0", 28 | "karma-jasmine": "^1.0.2", 29 | "karma-nativescript-launcher": "^0.4.0", 30 | "lazy": "1.0.11", 31 | "nativescript-css-loader": "~0.26.0", 32 | "nativescript-dev-typescript": "libs", 33 | "nativescript-dev-webpack": "^0.7.3", 34 | "raw-loader": "~0.5.1", 35 | "resolve-url-loader": "~2.1.0", 36 | "tns-platform-declarations": "^3.1.0", 37 | "tslint": "~5.4.3", 38 | "typescript": "~2.3.0", 39 | "webpack": "~3.2.0", 40 | "webpack-bundle-analyzer": "^2.8.2", 41 | "webpack-sources": "~1.0.1" 42 | }, 43 | "scripts": { 44 | "build.plugin": "cd ../src && npm run build", 45 | "ci.tslint": "npm i && tslint --config '../tslint.json' 'app/**/*.ts' --exclude '**/node_modules/**'", 46 | "ns-bundle": "ns-bundle", 47 | "publish-ios-bundle": "npm run ns-bundle --ios --publish-app", 48 | "generate-android-snapshot": "generate-android-snapshot --targetArchs arm,arm64,ia32 --install", 49 | "start-android-bundle": "npm run ns-bundle --android --run-app", 50 | "start-ios-bundle": "npm run ns-bundle --ios --run-app", 51 | "build-android-bundle": "npm run ns-bundle --android --build-app", 52 | "build-ios-bundle": "npm run ns-bundle --ios --build-app" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /demo/references.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": false, 6 | "removeComments": true, 7 | "noLib": false, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "lib": ["es2015", "dom"], 11 | "pretty": true, 12 | "allowUnreachableCode": false, 13 | "allowUnusedLabels": false, 14 | "noEmitHelpers": true, 15 | "noEmitOnError": false, 16 | "noImplicitAny": false, 17 | "noImplicitReturns": true, 18 | "noImplicitUseStrict": false, 19 | "noFallthroughCasesInSwitch": true, 20 | "baseUrl": ".", 21 | "paths": { 22 | "*": ["./node_modules/*"] 23 | } 24 | }, 25 | "exclude": ["node_modules", "platforms"], 26 | "compileOnSave": false 27 | } 28 | -------------------------------------------------------------------------------- /demo/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { resolve, join } = require("path"); 2 | 3 | const webpack = require("webpack"); 4 | const nsWebpack = require("nativescript-dev-webpack"); 5 | const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target"); 6 | const CopyWebpackPlugin = require("copy-webpack-plugin"); 7 | const ExtractTextPlugin = require("extract-text-webpack-plugin"); 8 | const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); 9 | 10 | 11 | const mainSheet = `app.css`; 12 | 13 | module.exports = env => { 14 | const platform = getPlatform(env); 15 | 16 | // Default destination inside platforms//... 17 | const path = resolve(nsWebpack.getAppPath(platform)); 18 | 19 | const entry = { 20 | // Discover entry module from package.json 21 | bundle: `./${nsWebpack.getEntryModule()}`, 22 | 23 | // Vendor entry with third-party libraries 24 | vendor: `./vendor`, 25 | 26 | // Entry for stylesheet with global application styles 27 | [mainSheet]: `./${mainSheet}`, 28 | }; 29 | 30 | const rules = getRules(); 31 | const plugins = getPlugins(platform, env); 32 | const extensions = getExtensions(platform); 33 | 34 | const config = { 35 | context: resolve("./app"), 36 | target: nativescriptTarget, 37 | entry, 38 | output: { 39 | pathinfo: true, 40 | path, 41 | libraryTarget: "commonjs2", 42 | filename: "[name].js", 43 | }, 44 | resolve: { 45 | extensions, 46 | 47 | // Resolve {N} system modules from tns-core-modules 48 | modules: [ 49 | "node_modules/tns-core-modules", 50 | "node_modules", 51 | ], 52 | 53 | alias: { 54 | '~': resolve("./app") 55 | }, 56 | }, 57 | node: { 58 | // Disable node shims that conflict with NativeScript 59 | "http": false, 60 | "timers": false, 61 | "setImmediate": false, 62 | "fs": "empty", 63 | }, 64 | module: { rules }, 65 | plugins, 66 | }; 67 | 68 | if (env.snapshot) { 69 | plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({ 70 | chunk: "vendor", 71 | projectRoot: __dirname, 72 | webpackConfig: config, 73 | targetArchs: ["arm", "arm64", "ia32"], 74 | tnsJavaClassesOptions: { packages: ["tns-core-modules" ] }, 75 | useLibs: false 76 | })); 77 | } 78 | 79 | return config; 80 | }; 81 | 82 | 83 | function getPlatform(env) { 84 | return env.android ? "android" : 85 | env.ios ? "ios" : 86 | () => { throw new Error("You need to provide a target platform!") }; 87 | } 88 | 89 | function getRules() { 90 | return [ 91 | { 92 | test: /\.html$|\.xml$/, 93 | use: [ 94 | "raw-loader", 95 | ] 96 | }, 97 | // Root stylesheet gets extracted with bundled dependencies 98 | { 99 | test: new RegExp(mainSheet), 100 | use: ExtractTextPlugin.extract([ 101 | { 102 | loader: "resolve-url-loader", 103 | options: { silent: true }, 104 | }, 105 | { 106 | loader: "nativescript-css-loader", 107 | options: { minimize: false } 108 | }, 109 | "nativescript-dev-webpack/platform-css-loader", 110 | ]), 111 | }, 112 | // Other CSS files get bundled using the raw loader 113 | { 114 | test: /\.css$/, 115 | exclude: new RegExp(mainSheet), 116 | use: [ 117 | "raw-loader", 118 | ] 119 | }, 120 | // SASS support 121 | { 122 | test: /\.scss$/, 123 | use: [ 124 | "raw-loader", 125 | "resolve-url-loader", 126 | "sass-loader", 127 | ] 128 | }, 129 | 130 | 131 | // Compile TypeScript files, replace templateUrl and styleUrls. 132 | { 133 | test: /\.ts$/, 134 | loaders: [ 135 | "awesome-typescript-loader", 136 | ] 137 | } 138 | 139 | ]; 140 | } 141 | 142 | function getPlugins(platform, env) { 143 | let plugins = [ 144 | new ExtractTextPlugin(mainSheet), 145 | 146 | // Vendor libs go to the vendor.js chunk 147 | new webpack.optimize.CommonsChunkPlugin({ 148 | name: ["vendor"], 149 | }), 150 | 151 | // Define useful constants like TNS_WEBPACK 152 | new webpack.DefinePlugin({ 153 | "global.TNS_WEBPACK": "true", 154 | }), 155 | 156 | // Copy assets to out dir. Add your own globs as needed. 157 | new CopyWebpackPlugin([ 158 | { from: mainSheet }, 159 | { from: "css/**" }, 160 | { from: "fonts/**" }, 161 | { from: "**/*.jpg" }, 162 | { from: "**/*.png" }, 163 | { from: "**/*.xml" }, 164 | ], { ignore: ["App_Resources/**"] }), 165 | 166 | // Generate a bundle starter script and activate it in package.json 167 | new nsWebpack.GenerateBundleStarterPlugin([ 168 | "./vendor", 169 | "./bundle", 170 | ]), 171 | 172 | // Generate report files for bundles content 173 | new BundleAnalyzerPlugin({ 174 | analyzerMode: "static", 175 | openAnalyzer: false, 176 | generateStatsFile: true, 177 | reportFilename: join(__dirname, "report", `report.html`), 178 | statsFilename: join(__dirname, "report", `stats.json`), 179 | }), 180 | ]; 181 | 182 | if (env.uglify) { 183 | plugins.push(new webpack.LoaderOptionsPlugin({ minimize: true })); 184 | 185 | // Work around an Android issue by setting compress = false 186 | const compress = platform !== "android"; 187 | plugins.push(new webpack.optimize.UglifyJsPlugin({ 188 | mangle: { except: nsWebpack.uglifyMangleExcludes }, 189 | compress, 190 | })); 191 | } 192 | 193 | return plugins; 194 | } 195 | 196 | // Resolve platform-specific modules like module.android.js 197 | function getExtensions(platform) { 198 | return Object.freeze([ 199 | `.${platform}.ts`, 200 | `.${platform}.js`, 201 | ".ts", 202 | ".js", 203 | ".css", 204 | `.${platform}.css`, 205 | ]); 206 | } 207 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 100, 3 | singleQuote: true, 4 | trailingComma: 'es5', 5 | bracketSpacing: true, 6 | jsxBracketSameLine: false, 7 | parser: 'typescript', 8 | semi: false, 9 | } 10 | -------------------------------------------------------------------------------- /publish/pack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SOURCE_DIR=../src; 4 | TO_SOURCE_DIR=src; 5 | PACK_DIR=package; 6 | ROOT_DIR=..; 7 | PUBLISH=--publish 8 | 9 | install(){ 10 | npm i 11 | } 12 | 13 | pack() { 14 | 15 | echo 'Clearing /src and /package...' 16 | node_modules/.bin/rimraf "$TO_SOURCE_DIR" 17 | node_modules/.bin/rimraf "$PACK_DIR" 18 | 19 | # copy src 20 | echo 'Copying src...' 21 | node_modules/.bin/ncp "$SOURCE_DIR" "$TO_SOURCE_DIR" 22 | 23 | # copy README & LICENSE to src 24 | echo 'Copying README and LICENSE to /src...' 25 | node_modules/.bin/ncp "$ROOT_DIR"/LICENSE "$TO_SOURCE_DIR"/LICENSE 26 | node_modules/.bin/ncp "$ROOT_DIR"/README.md "$TO_SOURCE_DIR"/README.md 27 | 28 | # compile package and copy files required by npm 29 | echo 'Building /src...' 30 | cd "$TO_SOURCE_DIR" 31 | node_modules/.bin/tsc 32 | cd .. 33 | 34 | echo 'Creating package...' 35 | # create package dir 36 | mkdir "$PACK_DIR" 37 | 38 | # create the package 39 | cd "$PACK_DIR" 40 | npm pack ../"$TO_SOURCE_DIR" 41 | 42 | # delete source directory used to create the package 43 | cd .. 44 | node_modules/.bin/rimraf "$TO_SOURCE_DIR" 45 | } 46 | 47 | install && pack -------------------------------------------------------------------------------- /publish/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nativescript-publish", 3 | "version": "1.0.0", 4 | "description": "Publish helper", 5 | "devDependencies": { 6 | "ncp": "^2.0.0", 7 | "rimraf": "^2.5.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /publish/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PACK_DIR=package; 4 | 5 | publish() { 6 | cd $PACK_DIR 7 | echo 'Publishing to npm...' 8 | npm publish *.tgz 9 | } 10 | 11 | ./pack.sh && publish -------------------------------------------------------------------------------- /src/.npmignore: -------------------------------------------------------------------------------- 1 | *.map 2 | *.ts 3 | !*.d.ts 4 | tsconfig.json -------------------------------------------------------------------------------- /src/constants/alert-types.ts: -------------------------------------------------------------------------------- 1 | export const AlertTypesConstants = { 2 | FORCE: 1, 3 | NONE: 3, 4 | OPTION: 2, 5 | } 6 | -------------------------------------------------------------------------------- /src/constants/app-store.ts: -------------------------------------------------------------------------------- 1 | export const AppStoreConstants = { 2 | ITUNES_BASE_URL: 'https://itunes.apple.com', 3 | } 4 | -------------------------------------------------------------------------------- /src/constants/google-play.ts: -------------------------------------------------------------------------------- 1 | export const GooglePlayConstants = { 2 | PLAY_STORE_PACKAGE_NOT_PUBLISHED_IDENTIFIER: ` 3 | We're sorry, the requested URL was not found on this server. 4 | `, 5 | PLAY_STORE_ROOT_WEB: `https://play.google.com/store/apps/details`, 6 | REGEX: { 7 | DATE: /itemprop="datePublished">\s*([\w\s,.]*)\s*<\/div>\s*<\/div>/gm, 8 | OS: /itemprop="operatingSystems">\s*([0-9.]*)[\w\s,]*<\/div>\s*<\/div>/gm, 9 | VERSION: /itemprop="softwareVersion">\s*([0-9.]*)\s*<\/div>\s*<\/div>/gm, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './alert-types' 2 | export * from './app-store' 3 | export * from './google-play' 4 | export * from './update-types' 5 | -------------------------------------------------------------------------------- /src/constants/update-types.ts: -------------------------------------------------------------------------------- 1 | export const UpdateTypesConstants = { 2 | MAJOR: 1, 3 | MINOR: 2, 4 | PATCH: 3, 5 | REVISION: 4, 6 | } 7 | -------------------------------------------------------------------------------- /src/helpers/app-store.helper.ts: -------------------------------------------------------------------------------- 1 | import { AppStoreConstants } from '../constants' 2 | import { IAppleStoreInfos, IAppleStoreResult } from '../interfaces' 3 | import { ResponseHelper } from './' 4 | 5 | export class AppStoreHelper { 6 | static getAppInfos(bundleID, countryCode?) { 7 | return AppStoreHelper._getLookupFile(bundleID, countryCode) 8 | .then(ResponseHelper.handleErrorStatus) 9 | .then(response => response.json()) 10 | .then(AppStoreHelper._parseResource) 11 | } 12 | 13 | private static _getLookupFile(bundleID, countryCode?) { 14 | return fetch(AppStoreHelper._getItunesLookupUrl(bundleID, countryCode)) 15 | } 16 | 17 | private static _parseResource(resource: IAppleStoreInfos): IAppleStoreResult { 18 | if (resource.resultCount === 0) return null 19 | return resource.results[0] 20 | } 21 | 22 | private static _getItunesLookupUrl(bundleId, countryCode?): string { 23 | let url = `${AppStoreConstants.ITUNES_BASE_URL}/lookup?bundleId=${bundleId}` 24 | if (countryCode) { 25 | url += `&hl=${countryCode}` 26 | } 27 | return url 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/helpers/google-play.helper.ts: -------------------------------------------------------------------------------- 1 | import { GooglePlayConstants } from '../constants' 2 | import { IGoogleStoreResult } from '../interfaces' 3 | import { ResponseHelper } from './' 4 | 5 | export class GooglePlayHelper { 6 | static getAppInfos(bundleId, countryCode?) { 7 | return GooglePlayHelper._getAppPage(bundleId, countryCode) 8 | .then(ResponseHelper.handleErrorStatus) 9 | .then(response => response.text()) 10 | .then(GooglePlayHelper._parseResource) 11 | } 12 | 13 | private static _getAppPage(bundleId, countryCode?) { 14 | return fetch(GooglePlayHelper._getStoreAppUrl(bundleId, countryCode)) 15 | } 16 | 17 | private static _parseResource(page): IGoogleStoreResult { 18 | const infos: any = {} 19 | Object.keys(GooglePlayConstants.REGEX).map(key => { 20 | // we force a new regex creation to allow multiple calls on the same regex 21 | const regEx = new RegExp(GooglePlayConstants.REGEX[key].source, 'gm').exec(page) 22 | infos[key.toLowerCase()] = regEx ? regEx[1] : null 23 | }) 24 | return infos 25 | } 26 | 27 | private static _getStoreAppUrl(bundleId, countryCode?): string { 28 | let url = `${GooglePlayConstants.PLAY_STORE_ROOT_WEB}?id=${bundleId}` 29 | if (countryCode) { 30 | url += `&hl=${countryCode}` 31 | } 32 | return url 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app-store.helper' 2 | export * from './google-play.helper' 3 | export * from './locales.helper' 4 | export * from './response.helper' 5 | export * from './version.helper' 6 | -------------------------------------------------------------------------------- /src/helpers/locales.helper.ts: -------------------------------------------------------------------------------- 1 | export class LocalesHelper { 2 | static currentLang = 'en' 3 | 4 | private static _defaultLang = 'en' 5 | private static _translations = { 6 | en: require('../i18n/en.json'), 7 | fr: require('../i18n/fr.json'), 8 | es: require('../i18n/es.json') 9 | } 10 | 11 | static translate(key: string): string { 12 | const translation = LocalesHelper._translations[LocalesHelper.currentLang][key] 13 | if (!translation) { 14 | console.error(`Can't find translation for ${key} in ${LocalesHelper.currentLang}`) 15 | return '' 16 | } 17 | return translation 18 | } 19 | 20 | static changeLang(key: string): void { 21 | key = key.toLowerCase() 22 | const langKey = LocalesHelper._translations[key] ? key : key.split('-')[0] 23 | if (!LocalesHelper._translations[langKey]) { 24 | LocalesHelper.currentLang = LocalesHelper._defaultLang 25 | console.error(` 26 | The lang ${langKey} is not yet supporter by the plugin, 27 | but you can contribute it on https://github.com/chronogolf/nativescript-store-update 28 | `) 29 | return 30 | } 31 | LocalesHelper.currentLang = langKey 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/helpers/response.helper.ts: -------------------------------------------------------------------------------- 1 | export class ResponseHelper { 2 | static handleErrorStatus(response: Response): Response { 3 | if (response.status >= 400) { 4 | throw new Error(`Unexpected HTTP status code (${response.status})`) 5 | } 6 | return response 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/helpers/version.helper.ts: -------------------------------------------------------------------------------- 1 | export class VersionHelper { 2 | static isHigher(left: string, right: string): boolean { 3 | return this._compareVersions(left, right) > 0 4 | } 5 | 6 | static isEqualOrHigher(left: string, right: string): boolean { 7 | return this._compareVersions(left, right) !== -1 8 | } 9 | 10 | // A.b.c.d 11 | static isMajorUpdate(left: string, right: string): boolean { 12 | return this._isIndexSectionHigher(left, right, 0) 13 | } 14 | 15 | // a.B.c.d 16 | static isMinorUpdate(left: string, right: string): boolean { 17 | return this._isIndexSectionHigher(left, right, 1) 18 | } 19 | 20 | // a.b.C.d 21 | static isPatchUpdate(left: string, right: string): boolean { 22 | return this._isIndexSectionHigher(left, right, 2) 23 | } 24 | 25 | // a.b.c.D 26 | static isRevisionUpdate(left: string, right: string): boolean { 27 | return this._isIndexSectionHigher(left, right, 3) 28 | } 29 | 30 | /* 31 | * Private 32 | */ 33 | 34 | private static _isIndexSectionHigher(left: string, right: string, index: number): boolean { 35 | const a = left.split('.') 36 | const b = right.split('.') 37 | 38 | return ( 39 | a.length > index && (b.length <= index || parseInt(a[index], 10) > parseInt(b[index], 10)) 40 | ) 41 | } 42 | 43 | private static _compareVersions(left: string, right: string): number { 44 | const a = left.split('.') 45 | const b = right.split('.') 46 | 47 | for (let i = 0; i < Math.max(a.length, b.length); i++) { 48 | const aInt = parseInt(a[i], 10) 49 | const bInt = parseInt(b[i], 10) 50 | if ((a[i] && !b[i] && aInt > 0) || aInt > bInt) return 1 51 | if ((b[i] && !a[i] && bInt > 0) || aInt < bInt) return -1 52 | } 53 | return 0 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "ALERT_TITLE": "Update available", 3 | "ALERT_MESSAGE": "A New Version is available in App Store.", 4 | "ALERT_UPDATE_BUTTON": "Update", 5 | "ALERT_SKIP_BUTTON": "Skip" 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "ALERT_TITLE": "Actualización disponible", 3 | "ALERT_MESSAGE": "Hay una nueva versión de la aplicación en el App Store.", 4 | "ALERT_UPDATE_BUTTON": "Actualizar", 5 | "ALERT_SKIP_BUTTON": "Omitir" 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "ALERT_TITLE": "Mise à jour disponible", 3 | "ALERT_MESSAGE": "Une nouvelle version est disponible sur le store", 4 | "ALERT_UPDATE_BUTTON": "Mettre à jour", 5 | "ALERT_SKIP_BUTTON": "Sauter cette version" 6 | } 7 | -------------------------------------------------------------------------------- /src/index.d.ts: -------------------------------------------------------------------------------- 1 | import { IStoreUpdateConfig } from './interfaces'; 2 | export * from './constants'; 3 | export * from './helpers'; 4 | export * from './interfaces'; 5 | export declare class StoreUpdate { 6 | private static _common; 7 | static init(config: IStoreUpdateConfig): void; 8 | static checkForUpdate(): void; 9 | protected static _openStore(): void; 10 | private static _extendResults(result); 11 | private static _trackViewUrl; 12 | } 13 | -------------------------------------------------------------------------------- /src/interfaces/app-store-result.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IAppleStoreResult { 2 | bundleId: string 3 | trackId: number 4 | version: string 5 | minimumOsVersion: string 6 | currentVersionReleaseDate: string 7 | trackViewUrl: string 8 | } 9 | 10 | /* 11 | N.B - results: 12 | Used to contain all versions, but now only contains the latest version. 13 | Still returns an instance of Array. 14 | */ 15 | export interface IAppleStoreInfos { 16 | resultCount: number 17 | results: IAppleStoreResult[] 18 | } 19 | -------------------------------------------------------------------------------- /src/interfaces/google-play-result.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IGoogleStoreResult { 2 | version: string 3 | os: string 4 | date: string 5 | } 6 | -------------------------------------------------------------------------------- /src/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app-store-result.interface' 2 | export * from './google-play-result.interface' 3 | export * from './store-update.config.interface' 4 | -------------------------------------------------------------------------------- /src/interfaces/store-update.config.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IStoreUpdateConfig { 2 | majorUpdateAlertType?: number 3 | minorUpdateAlertType?: number 4 | patchUpdateAlertType?: number 5 | revisionUpdateAlertType?: number 6 | notifyNbDaysAfterRelease?: number 7 | countryCode?: string 8 | onConfirmed?: any 9 | alertOptions?: AlertOptions 10 | } 11 | 12 | export interface AlertOptions { 13 | title?: string, 14 | message?: string, 15 | updateButton?: string, 16 | skipButton?: string 17 | } -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nativescript-store-update", 3 | "version": "2.0.0", 4 | "description": "Keep your {N} App updated.", 5 | "main": "store-update", 6 | "typings": "index.d.ts", 7 | "nativescript": { 8 | "platforms": { 9 | "android": "6.0.0", 10 | "ios": "6.0.0" 11 | } 12 | }, 13 | "scripts": { 14 | "tsc": "tsc -skipLibCheck", 15 | "build": "npm i && tsc", 16 | "setup": "npm i && cd ../demo && npm i && cd ../demo-angular && npm i && cd ../src", 17 | "test.android": "npm i && npm run tsc && npm run tslint && cd ../demo && tns build android && tns test android --justlaunch", 18 | "test.ios": "npm i && npm run tsc && npm run tslint && cd ../demo && tns build ios && tns test ios --justlaunch", 19 | "tslint": "cd .. && tslint \"**/*.ts\" --config tslint.json --exclude \"**/node_modules/**\" --exclude \"**/*.d.ts\" --exclude \"demo*/platforms/**\" --exclude \"**/hooks/**\"", 20 | "plugin.tscwatch": "npm run tsc -- -w", 21 | "demo.ios": "npm i && npm run tsc && cd ../demo && tns run ios --syncAllFiles", 22 | "build.ios": "npm i && npm run tsc && cd ../demo && tns build ios --syncAllFiles", 23 | "demo.android": "npm i && npm run tsc && cd ../demo && tns run android --syncAllFiles", 24 | "demo.reset": "cd ../demo && rimraf platforms hooks node_modules && npm i", 25 | "clean": "cd ../demo && rimraf hooks node_modules platforms && cd ../demo-angular && rimraf hooks node_modules platforms && cd ../src && rimraf node_modules", 26 | "ci.tslint": "npm i && tslint '**/*.ts' --config '../tslint.json' --exclude '**/node_modules/**'" 27 | }, 28 | "keywords": [ 29 | "NativeScript", 30 | "TypeScript", 31 | "JavaScript", 32 | "Android", 33 | "iOS", 34 | "Update", 35 | "Store", 36 | "App Store", 37 | "Chronogolf" 38 | ], 39 | "author": { 40 | "name": "Chronogolf", 41 | "email": "contact@chronogolf.com" 42 | }, 43 | "bugs": { 44 | "url": "https://github.com/chronogolf/nativescript-store-update/issues" 45 | }, 46 | "license": "Apache-2.0", 47 | "homepage": "https://github.com/chronogolf/nativescript-store-update", 48 | "readmeFilename": "README.md", 49 | "peerDependencies": { 50 | "@nativescript/core": "~7.0.0", 51 | "@nativescript/appversion": "~2.0.0" 52 | }, 53 | "devDependencies": { 54 | "@angular/core": "~10.1.0", 55 | "format": "^0.2.2", 56 | "prettier": "^1.6.0", 57 | "prompt": "^1.0.0", 58 | "rimraf": "^2.5.0", 59 | "rxjs": "^6.6.0", 60 | "@nativescript/core": "~7.0.0", 61 | "@nativescript/types": "~7.0.0", 62 | "@nativescript/webpack": "~3.0.0", 63 | "tslint": "^6.1.3", 64 | "tslint-config-prettier": "^1.18.0", 65 | "tslint-plugin-prettier": "^2.3.0", 66 | "typescript": "~3.9.0", 67 | "zone.js": "~0.11.1" 68 | }, 69 | "dependencies": { 70 | "@types/moment": "^2.13.0", 71 | "moment": "~2.29.0", 72 | "@nativescript/appversion": "~2.0.0" 73 | }, 74 | "bootstrapper": "nativescript-plugin-seed" 75 | } 76 | -------------------------------------------------------------------------------- /src/platforms/android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/platforms/android/README.md: -------------------------------------------------------------------------------- 1 | # Android permissions and dependencies 2 | 3 | * (Optional) Use AndroidManifest.xml to describe any permissions, features or other configuration specifics required or used by your plugin for Android. 4 | NOTE: The NativeScript CLI will not resolve any contradicting or duplicate entries during the merge. After the plugin is installed, you need to manually resolve such issues. 5 | 6 | * (Optional) Use include.gradle configuration to describe any native dependencies. If there are no such, this file can be removed. For more information, see the [include.gradle Specification](http://docs.nativescript.org/plugins/plugins#includegradle-specification) 7 | 8 | 9 | [Read more about nativescript plugins](http://docs.nativescript.org/plugins/plugins) -------------------------------------------------------------------------------- /src/platforms/android/include.gradle: -------------------------------------------------------------------------------- 1 | /* Include.gradle configuration: http://docs.nativescript.org/plugins/plugins#includegradle-specification */ 2 | 3 | android { 4 | productFlavors { 5 | "nativescript-store-update" { 6 | dimension "nativescript-store-update" 7 | } 8 | } 9 | } 10 | 11 | dependencies { 12 | // Describe plugin native Android dependencies like 13 | // compile "groupName:pluginName:ver" 14 | // EXAMPLE: compile "com.facebook.fresco:fresco:0.9.0+" 15 | } -------------------------------------------------------------------------------- /src/platforms/ios/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/platforms/ios/README.md: -------------------------------------------------------------------------------- 1 | # iOS permissions and dependencies 2 | 3 | 4 | * (Optional) Use Info.plist to describe any permissions, features or other configuration specifics required or used by your plugin for iOS. 5 | NOTE: The NativeScript CLI will not resolve any contradicting or duplicate entries during the merge. After the plugin is installed, you need to manually resolve such issues. 6 | * (Optional) Use build.xcconfig configuration to describe any plugin the native dependencies. If there are no such, this file can be removed. For more information, see the [build.xcconfig Specification section](http://docs.nativescript.org/plugins/plugins#buildxcconfig-specification). 7 | 8 | 9 | [Read more about nativescript plugins](http://docs.nativescript.org/plugins/plugins) -------------------------------------------------------------------------------- /src/platforms/ios/build.xcconfig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronogolf/nativescript-store-update/10d58971c6a5350b8988f443a1f47f3ba921a0bd/src/platforms/ios/build.xcconfig -------------------------------------------------------------------------------- /src/references.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/store-update.android.ts: -------------------------------------------------------------------------------- 1 | import { Application, Utils } from '@nativescript/core' 2 | 3 | import { GooglePlayHelper } from './helpers' 4 | import { IGoogleStoreResult, IStoreUpdateConfig } from './interfaces' 5 | import { StoreUpdateCommon } from './store-update.common' 6 | 7 | export * from './constants' 8 | export * from './helpers' 9 | export * from './interfaces' 10 | 11 | Application.on(Application.resumeEvent, () => { 12 | StoreUpdate.checkForUpdate() 13 | }) 14 | 15 | export class StoreUpdate { 16 | private static _common 17 | 18 | /* 19 | * Public 20 | */ 21 | 22 | static init(config: IStoreUpdateConfig) { 23 | if (StoreUpdate._common) throw new Error('NS Store Update already configured') 24 | StoreUpdate._common = new StoreUpdateCommon({ 25 | ...config, 26 | onConfirmed: StoreUpdate._openStore.bind(StoreUpdate), 27 | }) 28 | } 29 | 30 | static checkForUpdate() { 31 | if (!StoreUpdate._common) return 32 | GooglePlayHelper.getAppInfos(StoreUpdate._common.getBundleId()) 33 | .then(StoreUpdate._extendResults) 34 | .then(StoreUpdate._common.triggerAlertIfEligible.bind(StoreUpdate._common)) 35 | .catch(console.error) 36 | } 37 | 38 | /* 39 | * Protected 40 | */ 41 | 42 | protected static _openStore() { 43 | const storeUrl = `market://details?id=${StoreUpdate._common.getBundleId()}` 44 | Utils.openUrl(storeUrl) 45 | } 46 | 47 | /* 48 | * Private 49 | */ 50 | 51 | private static _extendResults(result: IGoogleStoreResult) { 52 | return { 53 | currentVersionReleaseDate: result.date, 54 | minimumOsVersion: result.os, 55 | systemVersion: android.os.Build.VERSION.RELEASE, 56 | version: result.version, 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/store-update.common.ts: -------------------------------------------------------------------------------- 1 | import * as moment from 'moment' 2 | import { Application, ApplicationSettings, Observable, Device, Dialogs, ConfirmOptions } from '@nativescript/core' 3 | 4 | import { getAppIdSync, getVersionCodeSync, getVersionNameSync } from '@nativescript/appversion' 5 | 6 | import { AlertTypesConstants, UpdateTypesConstants } from './constants' 7 | import { LocalesHelper, VersionHelper } from './helpers' 8 | import { IStoreUpdateConfig, AlertOptions } from './interfaces' 9 | 10 | declare var global: any 11 | const LAST_VERSION_SKIPPED_KEY = 'lastVersionSkipped' 12 | const defaultConfig: IStoreUpdateConfig = { 13 | countryCode: 'en', 14 | majorUpdateAlertType: AlertTypesConstants.FORCE, 15 | minorUpdateAlertType: AlertTypesConstants.OPTION, 16 | notifyNbDaysAfterRelease: 1, 17 | patchUpdateAlertType: AlertTypesConstants.NONE, 18 | revisionUpdateAlertType: AlertTypesConstants.NONE, 19 | alertOptions: null, 20 | onConfirmed: () => console.log('User confirmed!'), 21 | } 22 | 23 | export class StoreUpdateCommon { 24 | countryCode 25 | 26 | private _majorUpdateAlertType 27 | private _minorUpdateAlertType 28 | private _patchUpdateAlertType 29 | private _revisionUpdateAlertType 30 | private _notifyNbDaysAfterRelease 31 | private _onConfirmed 32 | private _alertOptions: AlertOptions 33 | 34 | constructor(config?: IStoreUpdateConfig) { 35 | if (config) this._init(config) 36 | } 37 | 38 | /* 39 | * Public 40 | */ 41 | 42 | getBundleId(): string { 43 | return getAppIdSync() 44 | } 45 | 46 | getLocalVersionNumber(): string { 47 | return `${getVersionNameSync()}.${getVersionCodeSync()}` 48 | } 49 | 50 | isEligibleForUpdate({ 51 | version, 52 | currentVersionReleaseDate, 53 | minimumOsVersion, 54 | systemVersion, 55 | }): boolean { 56 | if (!this._isUpdateCompatibleWithDeviceOS(systemVersion, minimumOsVersion)) { 57 | return false 58 | } 59 | if (!this._hasBeenReleasedLongerThanDelay(currentVersionReleaseDate)) return false 60 | if (this._isCurrentVersionSkipped(version)) return false 61 | if (!this._isAppStoreVersionNewer(version)) return false 62 | return true 63 | } 64 | 65 | setVersionAsSkipped(version: string) { 66 | ApplicationSettings.setString(LAST_VERSION_SKIPPED_KEY, version) 67 | } 68 | 69 | triggerAlertForUpdate(version: string) { 70 | return this.showAlertForUpdate(version).then((confirmed: boolean) => { 71 | if (confirmed) this._onConfirmed() 72 | else this.setVersionAsSkipped(version) 73 | }) 74 | } 75 | 76 | getAlertTypeForVersion(currentAppStoreVersion: string): number { 77 | const updateType = this._getUpdateTypeForVersion(currentAppStoreVersion) 78 | 79 | switch (updateType) { 80 | case UpdateTypesConstants.MAJOR: { 81 | return this._majorUpdateAlertType 82 | } 83 | case UpdateTypesConstants.MINOR: { 84 | return this._minorUpdateAlertType 85 | } 86 | case UpdateTypesConstants.PATCH: { 87 | return this._patchUpdateAlertType 88 | } 89 | case UpdateTypesConstants.REVISION: { 90 | return this._revisionUpdateAlertType 91 | } 92 | default: 93 | return AlertTypesConstants.OPTION 94 | } 95 | } 96 | 97 | buildDialogOptions({ skippable = true } = {}): ConfirmOptions { 98 | let options = { 99 | title: this._getMessage('title', 'ALERT_TITLE'), 100 | message: this._getMessage('message', 'ALERT_MESSAGE'), 101 | neutralButtonText: null, 102 | okButtonText: this._getMessage('updateButton', 'ALERT_UPDATE_BUTTON'), 103 | } 104 | 105 | if (skippable) { 106 | options = { 107 | ...options, 108 | neutralButtonText: this._getMessage('skipButton', 'ALERT_SKIP_BUTTON'), 109 | } 110 | } 111 | 112 | return options 113 | } 114 | 115 | showAlertForUpdate(version: string): Promise { 116 | const alertType = this.getAlertTypeForVersion(version) 117 | switch (alertType) { 118 | case AlertTypesConstants.FORCE: { 119 | const options: ConfirmOptions = this.buildDialogOptions({ skippable: false }) 120 | return Dialogs.confirm(options) 121 | } 122 | case AlertTypesConstants.OPTION: { 123 | const options: ConfirmOptions = this.buildDialogOptions() 124 | return Dialogs.confirm(options) 125 | } 126 | default: 127 | return Promise.reject(null) 128 | } 129 | } 130 | 131 | triggerAlertIfEligible(result) { 132 | if (this.isEligibleForUpdate(result)) { 133 | this.triggerAlertForUpdate(result.version) 134 | } 135 | } 136 | 137 | /* 138 | * Private 139 | */ 140 | 141 | private _init(config: IStoreUpdateConfig) { 142 | const conf = { 143 | ...defaultConfig, 144 | ...config, 145 | } 146 | 147 | this._majorUpdateAlertType = conf.majorUpdateAlertType 148 | this._minorUpdateAlertType = conf.minorUpdateAlertType 149 | this._patchUpdateAlertType = conf.patchUpdateAlertType 150 | this._revisionUpdateAlertType = conf.revisionUpdateAlertType 151 | this._notifyNbDaysAfterRelease = conf.notifyNbDaysAfterRelease 152 | this.countryCode = conf.countryCode 153 | this._onConfirmed = conf.onConfirmed 154 | this._alertOptions = conf.alertOptions 155 | 156 | LocalesHelper.changeLang(Device.language) 157 | } 158 | 159 | private _isAppStoreVersionNewer(storeVersion: string): boolean { 160 | if (storeVersion === null) return false 161 | return VersionHelper.isHigher(storeVersion, this.getLocalVersionNumber()) 162 | } 163 | 164 | private _isCurrentVersionSkipped(currentAppStoreVersion: string): boolean { 165 | const lastVersionSkipped = ApplicationSettings.getString(LAST_VERSION_SKIPPED_KEY) 166 | return currentAppStoreVersion === lastVersionSkipped 167 | } 168 | 169 | private _hasBeenReleasedLongerThanDelay(releaseDate: string): boolean { 170 | if (releaseDate === null) return false 171 | 172 | const daysSinceRelease = moment().diff(moment(new Date(releaseDate)), 'days') 173 | if (daysSinceRelease < this._notifyNbDaysAfterRelease) { 174 | console.log( 175 | `Your app has been released for ${daysSinceRelease} days, 176 | but we cannot prompt the user until 177 | ${this._notifyNbDaysAfterRelease} days have passed.` 178 | ) 179 | } 180 | 181 | return daysSinceRelease >= this._notifyNbDaysAfterRelease 182 | } 183 | 184 | private _isUpdateCompatibleWithDeviceOS( 185 | deviceVersion: string, 186 | minimumRequiredOSVersion: string 187 | ): boolean { 188 | if (minimumRequiredOSVersion === null) return true 189 | 190 | const isCompatible = VersionHelper.isEqualOrHigher(deviceVersion, minimumRequiredOSVersion) 191 | if (!isCompatible) console.log(`Device is incompatible with installed version of iOS.`) 192 | return isCompatible 193 | } 194 | 195 | private _getUpdateTypeForVersion(currentAppStoreVersion: string): number { 196 | const localVersion = this.getLocalVersionNumber() 197 | if (VersionHelper.isMajorUpdate(currentAppStoreVersion, localVersion)) { 198 | return UpdateTypesConstants.MAJOR 199 | } 200 | 201 | if (VersionHelper.isMinorUpdate(currentAppStoreVersion, localVersion)) { 202 | return UpdateTypesConstants.MINOR 203 | } 204 | 205 | if (VersionHelper.isPatchUpdate(currentAppStoreVersion, localVersion)) { 206 | return UpdateTypesConstants.PATCH 207 | } 208 | 209 | if (VersionHelper.isRevisionUpdate(currentAppStoreVersion, localVersion)) { 210 | return UpdateTypesConstants.REVISION 211 | } 212 | 213 | return -1 214 | } 215 | 216 | private _getMessage(alertOptionKey: string, fallbackTranslateKey: string): string { 217 | if (this._hasValidAlertOptionEntry(alertOptionKey)) return this._alertOptions[alertOptionKey] 218 | return LocalesHelper.translate(fallbackTranslateKey) 219 | } 220 | 221 | private _hasValidAlertOptionEntry(key) { 222 | if (!this._alertOptions) return false 223 | return this._alertOptions.hasOwnProperty(key) && this._alertOptions[key] !== '' 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/store-update.ios.ts: -------------------------------------------------------------------------------- 1 | import { Application, Http, Utils } from '@nativescript/core' 2 | import { AppStoreHelper } from './helpers' 3 | import { IAppleStoreResult, IStoreUpdateConfig } from './interfaces' 4 | import { StoreUpdateCommon } from './store-update.common' 5 | 6 | export * from './constants' 7 | export * from './helpers' 8 | export * from './interfaces' 9 | 10 | export class StoreUpdate { 11 | private static _common 12 | private static _trackViewUrl 13 | 14 | /* 15 | * Public 16 | */ 17 | 18 | static init(config: IStoreUpdateConfig) { 19 | if (StoreUpdate._common) throw new Error('NS Store Update already configured') 20 | StoreUpdate._common = new StoreUpdateCommon({ 21 | ...config, 22 | onConfirmed: StoreUpdate._openStore.bind(StoreUpdate), 23 | }) 24 | 25 | //Hook into resume event to check for version 26 | Application.on(Application.resumeEvent, function (args) { 27 | StoreUpdate.checkForUpdate(); 28 | }); 29 | } 30 | 31 | static checkForUpdate() { 32 | if (!StoreUpdate._common) return 33 | AppStoreHelper.getAppInfos(StoreUpdate._common.getBundleId(), StoreUpdate._common.countryCode) 34 | .then(StoreUpdate._extendResults) 35 | .then(StoreUpdate._common.triggerAlertIfEligible.bind(StoreUpdate._common)) 36 | .catch(e => console.error(e)) 37 | } 38 | 39 | /* 40 | * Protected 41 | */ 42 | 43 | protected static _openStore() { 44 | // App Path 45 | Utils.openUrl( 46 | NSURL.URLWithString(`itms-apps${StoreUpdate._trackViewUrl.slice(5)}`).absoluteString 47 | ) 48 | } 49 | 50 | /* 51 | * Private 52 | */ 53 | 54 | private static _extendResults(result: IAppleStoreResult) { 55 | StoreUpdate._trackViewUrl = result.trackViewUrl 56 | return { 57 | ...result, 58 | systemVersion: UIDevice.currentDevice.systemVersion, 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "declaration": true, 7 | "removeComments": true, 8 | "noLib": false, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "lib": ["es2017", "dom"], 12 | "sourceMap": true, 13 | "pretty": true, 14 | "allowUnreachableCode": false, 15 | "allowUnusedLabels": false, 16 | "noEmitHelpers": true, 17 | "noEmitOnError": false, 18 | "noImplicitAny": false, 19 | "noImplicitReturns": true, 20 | "noImplicitUseStrict": false, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "exclude": ["node_modules"], 24 | "compileOnSave": false 25 | } 26 | -------------------------------------------------------------------------------- /tslint-prettier.config.js: -------------------------------------------------------------------------------- 1 | const prettierRules = require('./prettier.config') 2 | module.exports = { 3 | rules: { 4 | prettier: [ true, prettierRules], 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:latest", 4 | "tslint-config-prettier", 5 | "tslint-plugin-prettier", 6 | "./tslint-prettier.config" 7 | ], 8 | "rules": { 9 | "curly": [true, "ignore-same-line"], 10 | "member-access": [ 11 | true, 12 | "no-public" 13 | ], 14 | "member-ordering": [ 15 | true, 16 | { 17 | "order": [ 18 | "public-static-field", 19 | "protected-static-field", 20 | "private-static-field", 21 | "public-instance-field", 22 | "protected-instance-field", 23 | "private-instance-field", 24 | "public-constructor", 25 | "protected-constructor", 26 | "private-constructor", 27 | "public-static-method", 28 | "public-instance-method", 29 | "protected-static-method", 30 | "protected-instance-method", 31 | "private-static-method", 32 | "private-instance-method" 33 | ] 34 | } 35 | ], 36 | "ordered-imports": false, 37 | "no-console": [false], 38 | "only-arrow-functions": [false], 39 | "no-submodule-imports": false, 40 | "no-var-requires": false, 41 | "variable-name": [ 42 | true, 43 | "ban-keywords", 44 | "check-format", 45 | "allow-leading-underscore", 46 | "allow-pascal-case" 47 | ], 48 | "object-literal-sort-keys": false 49 | } 50 | } 51 | --------------------------------------------------------------------------------