From 40068b11c025452848f7f224eeb4f0fe4463c2d2 Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Mon, 25 Jun 2018 17:29:34 +0300 Subject: [PATCH 01/12] Add file picker --- .../App_Resources/Android/AndroidManifest.xml | 5 +- demo/app/activity.android.ts | 51 +++++ src/nativechat.ts | 200 +++++++++++------- .../android/nativescript_nativechat.aar | Bin 1488 -> 0 bytes 4 files changed, 176 insertions(+), 80 deletions(-) create mode 100644 demo/app/activity.android.ts delete mode 100644 src/platforms/android/nativescript_nativechat.aar diff --git a/demo/app/App_Resources/Android/AndroidManifest.xml b/demo/app/App_Resources/Android/AndroidManifest.xml index 9db8321..08e1eb4 100644 --- a/demo/app/App_Resources/Android/AndroidManifest.xml +++ b/demo/app/App_Resources/Android/AndroidManifest.xml @@ -26,10 +26,11 @@ android:theme="@style/AppTheme"> + android:theme="@style/LaunchScreenTheme" + android:windowSoftInputMode="adjustResize"> diff --git a/demo/app/activity.android.ts b/demo/app/activity.android.ts new file mode 100644 index 0000000..5e4e0d1 --- /dev/null +++ b/demo/app/activity.android.ts @@ -0,0 +1,51 @@ +import { setActivityCallbacks, AndroidActivityCallbacks } from "tns-core-modules/ui/frame"; + + +const SELECT_FILE_RESULT_CODE = 100; + +@JavaProxy("org.myApp.MainActivity") +class Activity extends android.app.Activity { + private _callbacks: AndroidActivityCallbacks; + + public uploadCallback: android.webkit.ValueCallback; + + protected onCreate(savedInstanceState: android.os.Bundle): void { + if (!this._callbacks) { + setActivityCallbacks(this); + } + + this._callbacks.onCreate(this, savedInstanceState, super.onCreate); + this.uploadCallback = null; + } + + // public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { + // this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); + // } + + protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { + this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult); + if (requestCode === SELECT_FILE_RESULT_CODE) { + this.upload(resultCode, data); + } + } + + private upload(resultCode: number, data: android.content.Intent) { + if (this.uploadCallback === null) { + return; + } + + let uri = null; + if (resultCode == android.app.Activity.RESULT_OK) { + if (data !== null) { + if (android.os.Build.VERSION.SDK_INT >= 21) { + uri = android.net.Uri.parse(data.getDataString()); + } else { + uri = data.getData(); + } + } + } + + this.uploadCallback.onReceiveValue(uri); + this.uploadCallback = null; + } +} diff --git a/src/nativechat.ts b/src/nativechat.ts index 0892e9b..b57077e 100644 --- a/src/nativechat.ts +++ b/src/nativechat.ts @@ -2,113 +2,157 @@ import { GridLayout } from 'tns-core-modules/ui/layouts/grid-layout'; import { WebView } from 'tns-core-modules/ui/web-view'; import { isAndroid } from "tns-core-modules/platform" import { Observable, fromObject, EventData } from 'tns-core-modules/data/observable/observable'; +import * as application from 'tns-core-modules/application'; const builder = require('tns-core-modules/ui/builder'); const webchatUrl = 'https://webchat.nativechat.com/v1'; export interface NativeChatConfig { - botId: string; - channelId: string; - channelToken: string; - gtmId?: string; - session?: Session; - user?: User; + botId: string; + channelId: string; + channelToken: string; + gtmId?: string; + session?: Session; + user?: User; } export interface User { - id?: string; - name?: string; + id?: string; + name?: string; } export interface Session { - clear?: boolean; - context?: object; - userMessage?: string; + clear?: boolean; + context?: object; + userMessage?: string; } -export class NativeChat extends GridLayout { - private _webView: WebView; - private _config: NativeChatConfig; - - private webChatConfig: Observable; +class CustomWebChromeClient extends android.webkit.WebChromeClient { + constructor() { + super(); + return global.__native(this); + } - set config(value: NativeChatConfig) { - if (this._config && this._config.constructor.prototype instanceof Observable) { - (this._config).off('propertyChange', this.configPropertyChange.bind(this)); + onGeolocationPermissionsShowPrompt(origin:string, callback: android.webkit.GeolocationPermissions.ICallback) { + callback.invoke(origin, true, false); } - this._config = value; - this.updateUrl(); + onShowFileChooser( + webview: android.webkit.WebView, + filePathCallback: android.webkit.ValueCallback, + fileChooserParams + ) { + const activity = application.android.foregroundActivity; - if (this._config && this._config.constructor.prototype instanceof Observable) { - (this._config).on('propertyChange', this.configPropertyChange.bind(this)); - } - } - - get config(): NativeChatConfig { - return this._config; - } - - constructor() { - super(); - this.webChatConfig = fromObject({ url: '' }); - this._webView = builder.load(__dirname + '/nativechat.xml') as WebView; - this._webView.bindingContext = this.webChatConfig; - this._webView.on('loadFinished', this.webViewLoaded); - - this.addChild(this._webView); - } - - private webViewLoaded(args) { - var webview: WebView = args.object; - if (isAndroid) { - const settings = webview.android.getSettings(); - settings.setDomStorageEnabled(true); - settings.setDisplayZoomControls(false); + if (activity.uploadCallback != null) { + activity.uploadCallback.onReceiveValue(null); + activity.uploadCallback = null; + } + + activity.uploadCallback = filePathCallback; + + try { + const intent = fileChooserParams.createIntent(); + console.log(intent); + activity.startActivityForResult(intent, 100); + } catch (e) { + activity.uploadCallback = null; + android.widget.Toast.makeText(activity, 'Cannot open file chooser', android.widget.Toast.LENGTH_LONG).show(); + + return false; + } + + return true; } - } +} - private configPropertyChange(data: EventData): void { - this.updateUrl(); - } +export class NativeChat extends GridLayout { + private _webView: WebView; + private _config: NativeChatConfig; - private updateUrl(): void { - if (this._config && this._config.botId && this._config.channelId && this._config.channelToken) { - let url = `${webchatUrl}?botId=${encodeURIComponent(this._config.botId)}`; - url += `&channelId=${encodeURIComponent(this._config.channelId)}`; - url += `&token=${encodeURIComponent(this._config.channelToken)}`; + private webChatConfig: Observable; - if (this._config.user) { - if (this._config.user.name) { - url += `&user=${encodeURIComponent(JSON.stringify({ name: this._config.user.name }))}`; + set config(value: NativeChatConfig) { + if (this._config && this._config.constructor.prototype instanceof Observable) { + (this._config).off('propertyChange', this.configPropertyChange.bind(this)); } - if (this._config.user.id) { - url += `&senderId=${encodeURIComponent(this._config.user.id)}`; - } - } + this._config = value; + this.updateUrl(); - if (this._config.session) { - if (this._config.session.context) { - url += `&context=${encodeURIComponent(JSON.stringify(this._config.session.context))}`; + if (this._config && this._config.constructor.prototype instanceof Observable) { + (this._config).on('propertyChange', this.configPropertyChange.bind(this)); } + } - if (this._config.session.clear) { - url += `&newSession=true`; - } + get config(): NativeChatConfig { + return this._config; + } + + constructor() { + super(); + this.webChatConfig = fromObject({ url: '' }); + this._webView = builder.load(__dirname + '/nativechat.xml') as WebView; + this._webView.bindingContext = this.webChatConfig; + this._webView.on('loadFinished', this.webViewLoaded); + + this.addChild(this._webView); + } + + private webViewLoaded(args) { + var webview: WebView = args.object; + if (isAndroid) { + var settings = webview.android.getSettings(); + settings.setDomStorageEnabled(true); + settings.setDisplayZoomControls(false); + settings.setAppCacheEnabled(true); + settings.setDatabaseEnabled(true); - if (this._config.session.clear || this._config.session.userMessage) { - url += `&userMessage=${encodeURIComponent(this._config.session.userMessage || '')}`; + webview.android.setWebChromeClient(new CustomWebChromeClient()); } - } + } - if (this._config.gtmId != null) { - url += `>mId=${encodeURIComponent(this._config.gtmId)}`; - } + private configPropertyChange(data: EventData): void { + this.updateUrl(); + } - this.webChatConfig.set('url', url); - } else { - this.webChatConfig.set('url', ''); + private updateUrl(): void { + if (this._config && this._config.botId && this._config.channelId && this._config.channelToken) { + let url = `${webchatUrl}?botId=${encodeURIComponent(this._config.botId)}`; + url += `&channelId=${encodeURIComponent(this._config.channelId)}`; + url += `&token=${encodeURIComponent(this._config.channelToken)}`; + + if (this._config.user) { + if (this._config.user.name) { + url += `&user=${encodeURIComponent(JSON.stringify({ name: this._config.user.name }))}`; + } + + if (this._config.user.id) { + url += `&senderId=${encodeURIComponent(this._config.user.id)}`; + } + } + + if (this._config.session) { + if (this._config.session.context) { + url += `&context=${encodeURIComponent(JSON.stringify(this._config.session.context))}`; + } + + if (this._config.session.clear) { + url += `&newSession=true`; + } + + if (this._config.session.clear || this._config.session.userMessage) { + url += `&userMessage=${encodeURIComponent(this._config.session.userMessage || '')}`; + } + } + + if (this._config.gtmId != null) { + url += `>mId=${encodeURIComponent(this._config.gtmId)}`; + } + + this.webChatConfig.set('url', url); + } else { + this.webChatConfig.set('url', ''); + } } - } } diff --git a/src/platforms/android/nativescript_nativechat.aar b/src/platforms/android/nativescript_nativechat.aar deleted file mode 100644 index 507a2962332b0aba7cf9df6b5d0f242f14a66112..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1488 zcmWIWW@h1HVBp|jU~O9D6I8e9=w=261|>!Y24NuWn3qzNpPAyDn3tKBT3n)6k(-n2 zf12x%fxsT|U;K*Y(q9#Vepys}SE`t*dUM-CHO-r$e`>mYSr6_#`{s;6@K*hDasQr_ z=Jik4-SBFRV^6M)Kh0h~dvVU}HAN3{+m9qotJXR=TVl=1rw44NdQFtOz$n_OUsAxe zEYMYDs>RIoqpNF!9!< zCpVQ=%C&4!G_E_!v(bIujE}q4-IreyAn(5P+QGBZ0dPOE0sUC?=C-Rc69dCUAm#@8 zF*zr(xHz>~FDtQ#`$JlqVB&)Z4-yg*0#Y2M$UE^4NOZAOAEKFLaH_G1JQNLV5;+fy4Z~NaW6#Uu0dCvUe zR*vhJyC1DR!zz2J*P2O0_ow=bS><)N9xST=7;!Ffd-CgNAMU*u6HD5jJR$z;tF}Yh zJ7rlX<$r$q@BG}#?RWS6v1Y#CmLP6cc~5FFzp?rnv-q#qXS`g0YUb*8A+eo$9knm! z-`aMw@YuKLoyV`c-g>uBt9bF33o6MQU$^huAtmv48<*9OB=_bz?@QNeUa#+a|NYKY zj~DY2;#Y0{yXqP9+gATGYu>r(?AUhdPy58JH$G|pHvVrHF?IL5>sHH_{*y6&f6H(F zhHarWm)h91WzI}%xAv~HElR9f_`~VztOD`1>91ZUeq3!KKkq?|P2i;Dx4V|R?^^%l z|J3Ibt#?E}xhA!Lbb|Ncfz`u|&N zb5H6U^S{jW-&^x#szK6$W{+W5X*>2e_)>{$x`2LzTPp*7^{{{EH$#yqW&A8v%ZF_sV zhuQCv`qBKKIh%eTmU?jZ+{VO%uNKek;o{$hPti3K zLKwYx8SkyhQ7}^$n8uW8rY6A8fJjTA`~plq48UXr2CP6bNUx-#gqeV%#LSc&eSC`8 zfhK{{WJxhzWh_8tS$UZR)fA z8({#p%m&g10!td707;~*hpZ7>$bxl&H5xEO!c;1* From aa99ec5b1df2addd59cff967eb2fb8e31ea46631 Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Mon, 25 Jun 2018 17:56:19 +0300 Subject: [PATCH 02/12] ignore .aar file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5cfcb26..e48d043 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ publish/src publish/package demo/report/report.html demo/report/stats.json +src/platforms/android/nativescript_nativechat.aar From 41bf64efe97a8b88187e03d3611eacc62417bc0a Mon Sep 17 00:00:00 2001 From: gugulete Date: Mon, 25 Jun 2018 18:00:56 +0300 Subject: [PATCH 03/12] Enabled location picker on iOS --- demo/app/App_Resources/iOS/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demo/app/App_Resources/iOS/Info.plist b/demo/app/App_Resources/iOS/Info.plist index ea3e3ea..3efaecc 100644 --- a/demo/app/App_Resources/iOS/Info.plist +++ b/demo/app/App_Resources/iOS/Info.plist @@ -43,5 +43,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + NSLocationWhenInUseUsageDescription + Can I use your location? From 8c3e113f96b2812459c593ce8d4daab144297a88 Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Mon, 25 Jun 2018 19:04:09 +0300 Subject: [PATCH 04/12] Android file upload --- demo/app/activity.android.ts | 33 +++++++++-- publish/package-lock.json | 111 +++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 publish/package-lock.json diff --git a/demo/app/activity.android.ts b/demo/app/activity.android.ts index 5e4e0d1..a385d22 100644 --- a/demo/app/activity.android.ts +++ b/demo/app/activity.android.ts @@ -6,8 +6,8 @@ const SELECT_FILE_RESULT_CODE = 100; @JavaProxy("org.myApp.MainActivity") class Activity extends android.app.Activity { private _callbacks: AndroidActivityCallbacks; - - public uploadCallback: android.webkit.ValueCallback; + + public uploadCallback; protected onCreate(savedInstanceState: android.os.Bundle): void { if (!this._callbacks) { @@ -18,9 +18,29 @@ class Activity extends android.app.Activity { this.uploadCallback = null; } - // public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { - // this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); - // } + protected onSaveInstanceState(outState: android.os.Bundle): void { + this._callbacks.onSaveInstanceState(this, outState, super.onSaveInstanceState); + } + + protected onStart(): void { + this._callbacks.onStart(this, super.onStart); + } + + protected onStop(): void { + this._callbacks.onStop(this, super.onStop); + } + + protected onDestroy(): void { + this._callbacks.onDestroy(this, super.onDestroy); + } + + public onBackPressed(): void { + this._callbacks.onBackPressed(this, super.onBackPressed); + } + + public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { + this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); + } protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult); @@ -38,7 +58,8 @@ class Activity extends android.app.Activity { if (resultCode == android.app.Activity.RESULT_OK) { if (data !== null) { if (android.os.Build.VERSION.SDK_INT >= 21) { - uri = android.net.Uri.parse(data.getDataString()); + uri = Array.create(android.net.Uri, 1); + uri[0] = android.net.Uri.parse(data.getDataString()); } else { uri = data.getData(); } diff --git a/publish/package-lock.json b/publish/package-lock.json new file mode 100644 index 0000000..8431a8c --- /dev/null +++ b/publish/package-lock.json @@ -0,0 +1,111 @@ +{ + "name": "nativescript-publish", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} From 9dbc4b8dd74340896f4832882a3ad9344c340d27 Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Tue, 26 Jun 2018 17:14:25 +0300 Subject: [PATCH 05/12] Add location permissions request --- README.md | 78 ++++++++++++++--- .../App_Resources/Android/AndroidManifest.xml | 1 + demo/app/activity.android.ts | 25 ++++-- src/index.d.ts | 2 +- src/index.ts | 2 +- src/nativechat.ts | 83 ++++++++++++++----- 6 files changed, 151 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 1591652..01e9eec 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,26 @@ ## Prerequisites / Requirements -Follow the [instructions]() in our documentation to enable a mobile channel for your bot. +Follow the [instructions](https://docs.nativechat.com/docs/1.0/publishing/mobile) in our documentation to enable a mobile channel for your bot. ## Installation Run the following command from the root of your project: -``` +```bash tns plugin add @progress-nativechat/nativescript-nativechat ``` ## Usage -### JavaScript - -#### How to add the plugin using XML and binding +### JavaScript: How to add the plugin using XML and binding ```xml ``` + ```javascript exports.pageLoaded = function (args) { var page = args.object; @@ -47,7 +46,7 @@ exports.pageLoaded = function (args) { }; ``` -#### How to add the plugin directly through code +### JavaScript: How to add the plugin directly through code ```javascript var plugin = require('@progress-nativechat/nativescript-nativechat'); @@ -76,9 +75,7 @@ exports.pageLoaded = function (args) { }; ``` -### TypeScript - -#### How to add the plugin using XML and binding +### TypeScript: How to add the plugin using XML and binding ```xml ``` + ```typescript import { EventData, fromObject } from 'tns-core-modules/data/observable'; import { Page } from 'tns-core-modules/ui/page'; @@ -112,7 +110,8 @@ export function pageLoaded(args: EventData) { }); } ``` -#### How to add the plugin directly through code + +### TypeScript: How to add the plugin directly through code ```typescript import { EventData } from 'tns-core-modules/data/observable'; @@ -214,7 +213,6 @@ The *config* property should conform to the **NativeChatConfig** interface. | session | [Session](#session) | optional | Information about the user session. | | gtmId | string | optional | Google Tag Manager ID. Used in combination with the tracking property to track completed conversations. Check [here](https://docs.nativechat.com/docs/1.0/publishing/web/#gtmid-optional) for more information.| - #### User | Property | Type | | Description | @@ -230,6 +228,64 @@ The *config* property should conform to the **NativeChatConfig** interface. | context | object | optional | A JSON object containing entities to be merged with the conversation context. They can be used as any other entity within the cognitive flow. Be careful to not override other entities used in the cognitive flow. | | userMessage | string | optional | Used to send a message on the user's behalf if the session is cleared. | +## Enable Functionality + +### Android: File Picker + + [extend application activity](https://docs.nativescript.org/angular/core-concepts/android-runtime/advanced-topics/extend-application-activity#extending-activity) + +Add the following code to the *onActivityResult* method: + +```typescript +import { NativeChat } from "@progress-nativechat/nativescript-nativechat"; + +protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { + this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult); + if (requestCode === NativeChat.SELECT_FILE_RESULT_CODE) { + this.upload(resultCode, data); + } +} + +private upload(resultCode: number, data: android.content.Intent) { + if (this.uploadCallback === null) { + return; + } + + let uri = null; + if (resultCode == android.app.Activity.RESULT_OK) { + if (data !== null) { + if (android.os.Build.VERSION.SDK_INT >= 21) { + uri = Array.create(android.net.Uri, 1); + uri[0] = android.net.Uri.parse(data.getDataString()); + } else { + uri = data.getData(); + } + } + } + + this.uploadCallback.onReceiveValue(uri); + this.uploadCallback = null; +} +``` + +### Android: Location Picker + +### iOS: Location Picker + +You have to requiest authorization from the user to use his location. Add *NSLocationWhenInUseUsageDescription* key in the *app/App_Resources/iOS/Info.plist* file. + +```xml + + + + + ... + NSLocationWhenInUseUsageDescription + Can I use your location? + + +``` + ## License Apache License Version 2.0, January 2004 diff --git a/demo/app/App_Resources/Android/AndroidManifest.xml b/demo/app/App_Resources/Android/AndroidManifest.xml index 08e1eb4..020ed5f 100644 --- a/demo/app/App_Resources/Android/AndroidManifest.xml +++ b/demo/app/App_Resources/Android/AndroidManifest.xml @@ -17,6 +17,7 @@ + ; protected onCreate(savedInstanceState: android.os.Bundle): void { if (!this._callbacks) { @@ -40,11 +41,21 @@ class Activity extends android.app.Activity { public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); + + if (requestCode === NativeChat.REQUEST_LOCATION_CODE) { + if (grantResults.length > 0 && grantResults[0] === android.content.pm.PackageManager.PERMISSION_GRANTED) { + if (this.geolocationCallback !== null && this.geolocationOrigin !== null) { + this.geolocationCallback.invoke(this.geolocationOrigin, true, false); + this.geolocationCallback = null; + this.geolocationOrigin = null; + } + } + } } protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult); - if (requestCode === SELECT_FILE_RESULT_CODE) { + if (requestCode === NativeChat.SELECT_FILE_RESULT_CODE) { this.upload(resultCode, data); } } @@ -58,7 +69,7 @@ class Activity extends android.app.Activity { if (resultCode == android.app.Activity.RESULT_OK) { if (data !== null) { if (android.os.Build.VERSION.SDK_INT >= 21) { - uri = Array.create(android.net.Uri, 1); + uri = Array.create(android.net.Uri, 1); uri[0] = android.net.Uri.parse(data.getDataString()); } else { uri = data.getData(); diff --git a/src/index.d.ts b/src/index.d.ts index 5a2c45d..db73979 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1 +1 @@ -export { NativeChat, NativeChatConfig, Session, User } from './nativechat'; +export { NativeChat, NativeChatConfig, Session, User, IGeolocationActivity, IUploadFileActivity } from './nativechat'; diff --git a/src/index.ts b/src/index.ts index 114cffe..65db5ed 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1 @@ -export { NativeChat, NativeChatConfig, Session, User } from './nativechat'; \ No newline at end of file +export { NativeChat, NativeChatConfig, Session, User, IGeolocationActivity, IUploadFileActivity } from './nativechat'; \ No newline at end of file diff --git a/src/nativechat.ts b/src/nativechat.ts index b57077e..7709fbd 100644 --- a/src/nativechat.ts +++ b/src/nativechat.ts @@ -3,10 +3,13 @@ import { WebView } from 'tns-core-modules/ui/web-view'; import { isAndroid } from "tns-core-modules/platform" import { Observable, fromObject, EventData } from 'tns-core-modules/data/observable/observable'; import * as application from 'tns-core-modules/application'; +import * as builder from 'tns-core-modules/ui/builder' -const builder = require('tns-core-modules/ui/builder'); const webchatUrl = 'https://webchat.nativechat.com/v1'; +const PERMISSION_GRANTED = android.content.pm.PackageManager.PERMISSION_GRANTED; +const ACCESS_FINE_LOCATION = (android as any).Manifest.permission.ACCESS_FINE_LOCATION; + export interface NativeChatConfig { botId: string; channelId: string; @@ -27,46 +30,86 @@ export interface Session { userMessage?: string; } -class CustomWebChromeClient extends android.webkit.WebChromeClient { - constructor() { - super(); - return global.__native(this); - } +export interface IUploadFileActivity { + uploadCallback: android.webkit.ValueCallback; +} - onGeolocationPermissionsShowPrompt(origin:string, callback: android.webkit.GeolocationPermissions.ICallback) { - callback.invoke(origin, true, false); +export interface IGeolocationActivity { + geolocationCallback: android.webkit.GeolocationPermissions.ICallback; + geolocationOrigin: string; +} + +class CustomWebChromeClient extends android.webkit.WebChromeClient { + onGeolocationPermissionsShowPrompt(origin: string, callback: android.webkit.GeolocationPermissions.ICallback) { + const context = application.android.currentContext; + + context.geolocationCallback = null; + context.geolocationOrigin = null; + + const fineLocationPermission = context.checkSelfPermission(ACCESS_FINE_LOCATION); + if (fineLocationPermission !== PERMISSION_GRANTED) { + context.geolocationCallback = callback; + context.geolocationOrigin = origin; + try { + context.requestPermissions([ACCESS_FINE_LOCATION], NativeChat.REQUEST_LOCATION_CODE); + } catch (e) { + context.geolocationCallback = null; + context.geolocationOrigin = null; + android.widget.Toast.makeText(context, 'Cannot request location permissions.', android.widget.Toast.LENGTH_LONG).show(); + } + } else { + callback.invoke(origin, true, false); + } } onShowFileChooser( webview: android.webkit.WebView, filePathCallback: android.webkit.ValueCallback, fileChooserParams - ) { - const activity = application.android.foregroundActivity; + ): boolean { + const context = application.android.currentContext; - if (activity.uploadCallback != null) { - activity.uploadCallback.onReceiveValue(null); - activity.uploadCallback = null; + if (context.uploadCallback != null) { + context.uploadCallback.onReceiveValue(null); + context.uploadCallback = null; } - activity.uploadCallback = filePathCallback; + context.uploadCallback = filePathCallback; try { const intent = fileChooserParams.createIntent(); console.log(intent); - activity.startActivityForResult(intent, 100); + context.startActivityForResult(intent, NativeChat.SELECT_FILE_RESULT_CODE); } catch (e) { - activity.uploadCallback = null; - android.widget.Toast.makeText(activity, 'Cannot open file chooser', android.widget.Toast.LENGTH_LONG).show(); - + context.uploadCallback = null; + android.widget.Toast.makeText(context, 'Cannot open file chooser', android.widget.Toast.LENGTH_LONG).show(); + return false; } - + return true; } + + shouldOverrideUrlLoading(webview: android.webkit.WebView, url: string): boolean { + if (url !== null && (url.startsWith("http://") || url.startsWith("https://"))) { + const context = application.android.currentContext; + + try { + context.startActivity(new android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(url))); + return true; + } catch (error) { + android.widget.Toast.makeText(context, 'Cannot open url', android.widget.Toast.LENGTH_LONG).show(); + } + } + + return false; + } } export class NativeChat extends GridLayout { + public static SELECT_FILE_RESULT_CODE = 100; + public static REQUEST_LOCATION_CODE = 200; + private _webView: WebView; private _config: NativeChatConfig; @@ -106,7 +149,7 @@ export class NativeChat extends GridLayout { settings.setDomStorageEnabled(true); settings.setDisplayZoomControls(false); settings.setAppCacheEnabled(true); - settings.setDatabaseEnabled(true); + settings.setDatabaseEnabled(true); webview.android.setWebChromeClient(new CustomWebChromeClient()); } From 2fbf5cc1824f862c0f69d67e3a2d2f471fa8bcbd Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Tue, 26 Jun 2018 17:37:14 +0300 Subject: [PATCH 06/12] refactor --- src/android/geolocation-activity.d.ts | 4 + src/android/geolocation-activity.ts | 4 + src/android/index.d.ts | 2 + src/android/index.ts | 2 + src/android/nativechat-web-chrome-client.d.ts | 5 + src/android/nativechat-web-chrome-client.ts | 72 ++++++++++++ src/android/upload-file-activity.d.ts | 3 + src/android/upload-file-activity.ts | 3 + src/index.d.ts | 4 +- src/index.ts | 5 +- src/models/index.d.ts | 3 + src/models/index.ts | 3 + src/models/nativechat-config.d.ts | 10 ++ src/models/nativechat-config.ts | 11 ++ src/models/session.d.ts | 5 + src/models/session.ts | 5 + src/models/user.d.ts | 4 + src/models/user.ts | 4 + src/nativechat.ts | 109 +----------------- 19 files changed, 153 insertions(+), 105 deletions(-) create mode 100644 src/android/geolocation-activity.d.ts create mode 100644 src/android/geolocation-activity.ts create mode 100644 src/android/index.d.ts create mode 100644 src/android/index.ts create mode 100644 src/android/nativechat-web-chrome-client.d.ts create mode 100644 src/android/nativechat-web-chrome-client.ts create mode 100644 src/android/upload-file-activity.d.ts create mode 100644 src/android/upload-file-activity.ts create mode 100644 src/models/index.d.ts create mode 100644 src/models/index.ts create mode 100644 src/models/nativechat-config.d.ts create mode 100644 src/models/nativechat-config.ts create mode 100644 src/models/session.d.ts create mode 100644 src/models/session.ts create mode 100644 src/models/user.d.ts create mode 100644 src/models/user.ts diff --git a/src/android/geolocation-activity.d.ts b/src/android/geolocation-activity.d.ts new file mode 100644 index 0000000..945f25b --- /dev/null +++ b/src/android/geolocation-activity.d.ts @@ -0,0 +1,4 @@ +export interface IGeolocationActivity { + geolocationCallback: android.webkit.GeolocationPermissions.ICallback; + geolocationOrigin: string; +} diff --git a/src/android/geolocation-activity.ts b/src/android/geolocation-activity.ts new file mode 100644 index 0000000..945f25b --- /dev/null +++ b/src/android/geolocation-activity.ts @@ -0,0 +1,4 @@ +export interface IGeolocationActivity { + geolocationCallback: android.webkit.GeolocationPermissions.ICallback; + geolocationOrigin: string; +} diff --git a/src/android/index.d.ts b/src/android/index.d.ts new file mode 100644 index 0000000..4dcf523 --- /dev/null +++ b/src/android/index.d.ts @@ -0,0 +1,2 @@ +export { IGeolocationActivity } from './geolocation-activity'; +export { IUploadFileActivity } from './upload-file-activity'; diff --git a/src/android/index.ts b/src/android/index.ts new file mode 100644 index 0000000..eea8a5f --- /dev/null +++ b/src/android/index.ts @@ -0,0 +1,2 @@ +export { IGeolocationActivity } from './geolocation-activity'; +export { IUploadFileActivity } from './upload-file-activity'; \ No newline at end of file diff --git a/src/android/nativechat-web-chrome-client.d.ts b/src/android/nativechat-web-chrome-client.d.ts new file mode 100644 index 0000000..848c6d6 --- /dev/null +++ b/src/android/nativechat-web-chrome-client.d.ts @@ -0,0 +1,5 @@ +export declare class NativeChatWebChromeClient extends android.webkit.WebChromeClient { + onGeolocationPermissionsShowPrompt(origin: string, callback: android.webkit.GeolocationPermissions.ICallback): void; + onShowFileChooser(webview: android.webkit.WebView, filePathCallback: android.webkit.ValueCallback, fileChooserParams: any): boolean; + shouldOverrideUrlLoading(webview: android.webkit.WebView, url: string): boolean; +} diff --git a/src/android/nativechat-web-chrome-client.ts b/src/android/nativechat-web-chrome-client.ts new file mode 100644 index 0000000..d8d58df --- /dev/null +++ b/src/android/nativechat-web-chrome-client.ts @@ -0,0 +1,72 @@ +import * as application from 'tns-core-modules/application'; +import { NativeChat } from '../nativechat'; + +const PERMISSION_GRANTED = android.content.pm.PackageManager.PERMISSION_GRANTED; +const ACCESS_FINE_LOCATION = (android as any).Manifest.permission.ACCESS_FINE_LOCATION; + +export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { + onGeolocationPermissionsShowPrompt(origin: string, callback: android.webkit.GeolocationPermissions.ICallback) { + const context = application.android.currentContext; + + context.geolocationCallback = null; + context.geolocationOrigin = null; + + const fineLocationPermission = context.checkSelfPermission(ACCESS_FINE_LOCATION); + if (fineLocationPermission !== PERMISSION_GRANTED) { + context.geolocationCallback = callback; + context.geolocationOrigin = origin; + try { + context.requestPermissions([ACCESS_FINE_LOCATION], NativeChat.REQUEST_LOCATION_CODE); + } catch (e) { + context.geolocationCallback = null; + context.geolocationOrigin = null; + android.widget.Toast.makeText(context, 'Cannot request location permissions.', android.widget.Toast.LENGTH_LONG).show(); + } + } else { + callback.invoke(origin, true, false); + } + } + + onShowFileChooser( + webview: android.webkit.WebView, + filePathCallback: android.webkit.ValueCallback, + fileChooserParams + ): boolean { + const context = application.android.currentContext; + + if (context.uploadCallback != null) { + context.uploadCallback.onReceiveValue(null); + context.uploadCallback = null; + } + + context.uploadCallback = filePathCallback; + + try { + const intent = fileChooserParams.createIntent(); + console.log(intent); + context.startActivityForResult(intent, NativeChat.SELECT_FILE_RESULT_CODE); + } catch (e) { + context.uploadCallback = null; + android.widget.Toast.makeText(context, 'Cannot open file chooser', android.widget.Toast.LENGTH_LONG).show(); + + return false; + } + + return true; + } + + shouldOverrideUrlLoading(webview: android.webkit.WebView, url: string): boolean { + if (url !== null && (url.startsWith("http://") || url.startsWith("https://"))) { + const context = application.android.currentContext; + + try { + context.startActivity(new android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(url))); + return true; + } catch (error) { + android.widget.Toast.makeText(context, 'Cannot open url', android.widget.Toast.LENGTH_LONG).show(); + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/android/upload-file-activity.d.ts b/src/android/upload-file-activity.d.ts new file mode 100644 index 0000000..fd31c90 --- /dev/null +++ b/src/android/upload-file-activity.d.ts @@ -0,0 +1,3 @@ +export interface IUploadFileActivity { + uploadCallback: android.webkit.ValueCallback; +} diff --git a/src/android/upload-file-activity.ts b/src/android/upload-file-activity.ts new file mode 100644 index 0000000..fd31c90 --- /dev/null +++ b/src/android/upload-file-activity.ts @@ -0,0 +1,3 @@ +export interface IUploadFileActivity { + uploadCallback: android.webkit.ValueCallback; +} diff --git a/src/index.d.ts b/src/index.d.ts index db73979..46c5d42 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1 +1,3 @@ -export { NativeChat, NativeChatConfig, Session, User, IGeolocationActivity, IUploadFileActivity } from './nativechat'; +export { NativeChat } from './nativechat'; +export { NativeChatConfig, Session, User } from './models'; +export { IGeolocationActivity, IUploadFileActivity } from './android'; diff --git a/src/index.ts b/src/index.ts index 65db5ed..3e24faa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,4 @@ -export { NativeChat, NativeChatConfig, Session, User, IGeolocationActivity, IUploadFileActivity } from './nativechat'; \ No newline at end of file +export { NativeChat } from './nativechat'; +export { NativeChatConfig, Session, User } from './models'; +export { IGeolocationActivity, IUploadFileActivity } from './android'; + diff --git a/src/models/index.d.ts b/src/models/index.d.ts new file mode 100644 index 0000000..d71ef6f --- /dev/null +++ b/src/models/index.d.ts @@ -0,0 +1,3 @@ +export { Session } from "./session"; +export { User } from "./user"; +export { NativeChatConfig } from "./nativechat-config"; diff --git a/src/models/index.ts b/src/models/index.ts new file mode 100644 index 0000000..4feb955 --- /dev/null +++ b/src/models/index.ts @@ -0,0 +1,3 @@ +export { Session } from "./session"; +export { User } from "./user"; +export { NativeChatConfig } from "./nativechat-config"; \ No newline at end of file diff --git a/src/models/nativechat-config.d.ts b/src/models/nativechat-config.d.ts new file mode 100644 index 0000000..ed13c57 --- /dev/null +++ b/src/models/nativechat-config.d.ts @@ -0,0 +1,10 @@ +import { Session } from "./session"; +import { User } from "./user"; +export interface NativeChatConfig { + botId: string; + channelId: string; + channelToken: string; + gtmId?: string; + session?: Session; + user?: User; +} diff --git a/src/models/nativechat-config.ts b/src/models/nativechat-config.ts new file mode 100644 index 0000000..137f7cf --- /dev/null +++ b/src/models/nativechat-config.ts @@ -0,0 +1,11 @@ +import { Session } from "./session"; +import { User } from "./user"; + +export interface NativeChatConfig { + botId: string; + channelId: string; + channelToken: string; + gtmId?: string; + session?: Session; + user?: User; +} diff --git a/src/models/session.d.ts b/src/models/session.d.ts new file mode 100644 index 0000000..c96e48c --- /dev/null +++ b/src/models/session.d.ts @@ -0,0 +1,5 @@ +export interface Session { + clear?: boolean; + context?: object; + userMessage?: string; +} diff --git a/src/models/session.ts b/src/models/session.ts new file mode 100644 index 0000000..c96e48c --- /dev/null +++ b/src/models/session.ts @@ -0,0 +1,5 @@ +export interface Session { + clear?: boolean; + context?: object; + userMessage?: string; +} diff --git a/src/models/user.d.ts b/src/models/user.d.ts new file mode 100644 index 0000000..46401b2 --- /dev/null +++ b/src/models/user.d.ts @@ -0,0 +1,4 @@ +export interface User { + id?: string; + name?: string; +} diff --git a/src/models/user.ts b/src/models/user.ts new file mode 100644 index 0000000..46401b2 --- /dev/null +++ b/src/models/user.ts @@ -0,0 +1,4 @@ +export interface User { + id?: string; + name?: string; +} diff --git a/src/nativechat.ts b/src/nativechat.ts index 7709fbd..089f2f6 100644 --- a/src/nativechat.ts +++ b/src/nativechat.ts @@ -2,110 +2,13 @@ import { GridLayout } from 'tns-core-modules/ui/layouts/grid-layout'; import { WebView } from 'tns-core-modules/ui/web-view'; import { isAndroid } from "tns-core-modules/platform" import { Observable, fromObject, EventData } from 'tns-core-modules/data/observable/observable'; -import * as application from 'tns-core-modules/application'; -import * as builder from 'tns-core-modules/ui/builder' + import * as builder from 'tns-core-modules/ui/builder' + +import { NativeChatConfig } from './models'; +import { NativeChatWebChromeClient } from './android/nativechat-web-chrome-client'; const webchatUrl = 'https://webchat.nativechat.com/v1'; - -const PERMISSION_GRANTED = android.content.pm.PackageManager.PERMISSION_GRANTED; -const ACCESS_FINE_LOCATION = (android as any).Manifest.permission.ACCESS_FINE_LOCATION; - -export interface NativeChatConfig { - botId: string; - channelId: string; - channelToken: string; - gtmId?: string; - session?: Session; - user?: User; -} - -export interface User { - id?: string; - name?: string; -} - -export interface Session { - clear?: boolean; - context?: object; - userMessage?: string; -} - -export interface IUploadFileActivity { - uploadCallback: android.webkit.ValueCallback; -} - -export interface IGeolocationActivity { - geolocationCallback: android.webkit.GeolocationPermissions.ICallback; - geolocationOrigin: string; -} - -class CustomWebChromeClient extends android.webkit.WebChromeClient { - onGeolocationPermissionsShowPrompt(origin: string, callback: android.webkit.GeolocationPermissions.ICallback) { - const context = application.android.currentContext; - - context.geolocationCallback = null; - context.geolocationOrigin = null; - - const fineLocationPermission = context.checkSelfPermission(ACCESS_FINE_LOCATION); - if (fineLocationPermission !== PERMISSION_GRANTED) { - context.geolocationCallback = callback; - context.geolocationOrigin = origin; - try { - context.requestPermissions([ACCESS_FINE_LOCATION], NativeChat.REQUEST_LOCATION_CODE); - } catch (e) { - context.geolocationCallback = null; - context.geolocationOrigin = null; - android.widget.Toast.makeText(context, 'Cannot request location permissions.', android.widget.Toast.LENGTH_LONG).show(); - } - } else { - callback.invoke(origin, true, false); - } - } - - onShowFileChooser( - webview: android.webkit.WebView, - filePathCallback: android.webkit.ValueCallback, - fileChooserParams - ): boolean { - const context = application.android.currentContext; - - if (context.uploadCallback != null) { - context.uploadCallback.onReceiveValue(null); - context.uploadCallback = null; - } - - context.uploadCallback = filePathCallback; - - try { - const intent = fileChooserParams.createIntent(); - console.log(intent); - context.startActivityForResult(intent, NativeChat.SELECT_FILE_RESULT_CODE); - } catch (e) { - context.uploadCallback = null; - android.widget.Toast.makeText(context, 'Cannot open file chooser', android.widget.Toast.LENGTH_LONG).show(); - - return false; - } - - return true; - } - - shouldOverrideUrlLoading(webview: android.webkit.WebView, url: string): boolean { - if (url !== null && (url.startsWith("http://") || url.startsWith("https://"))) { - const context = application.android.currentContext; - - try { - context.startActivity(new android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(url))); - return true; - } catch (error) { - android.widget.Toast.makeText(context, 'Cannot open url', android.widget.Toast.LENGTH_LONG).show(); - } - } - - return false; - } -} - + export class NativeChat extends GridLayout { public static SELECT_FILE_RESULT_CODE = 100; public static REQUEST_LOCATION_CODE = 200; @@ -151,7 +54,7 @@ export class NativeChat extends GridLayout { settings.setAppCacheEnabled(true); settings.setDatabaseEnabled(true); - webview.android.setWebChromeClient(new CustomWebChromeClient()); + webview.android.setWebChromeClient(new NativeChatWebChromeClient()); } } From 885cff479845cf51226302c5aa2965ab29870758 Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Wed, 27 Jun 2018 11:09:50 +0300 Subject: [PATCH 07/12] Android chat urls are opened in browser --- demo/package-lock.json | 152 +++++++++--------- src/android/nativechat-web-chrome-client.d.ts | 1 - src/android/nativechat-web-chrome-client.ts | 16 -- src/android/nativechat-web-view-client.d.ts | 3 + src/android/nativechat-web-view-client.ts | 21 +++ src/nativechat.ts | 15 +- src/platforms/android/README.md | 4 +- 7 files changed, 112 insertions(+), 100 deletions(-) create mode 100644 src/android/nativechat-web-view-client.d.ts create mode 100644 src/android/nativechat-web-view-client.ts diff --git a/demo/package-lock.json b/demo/package-lock.json index e2ef61d..30704ef 100644 --- a/demo/package-lock.json +++ b/demo/package-lock.json @@ -25,56 +25,56 @@ "version": "6.0.5", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.9.0" } }, "@angular/compiler": { "version": "6.0.5", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.9.0" } }, "@angular/core": { "version": "6.0.5", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.9.0" } }, "@angular/forms": { "version": "6.0.5", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.9.0" } }, "@angular/http": { "version": "6.0.5", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.9.0" } }, "@angular/platform-browser": { "version": "6.0.5", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.9.0" } }, "@angular/platform-browser-dynamic": { "version": "6.0.5", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.9.0" } }, "@angular/router": { "version": "6.0.5", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.9.0" } }, "ansi-regex": { @@ -89,7 +89,7 @@ "version": "1.0.10", "bundled": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "async": { @@ -100,20 +100,20 @@ "version": "6.26.0", "bundled": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "chalk": { "version": "1.1.3", "bundled": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } } } @@ -126,7 +126,7 @@ "version": "1.1.11", "bundled": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -138,23 +138,23 @@ "version": "2.3.2", "bundled": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.3.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "dependencies": { "ansi-styles": { "version": "3.2.1", "bundled": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "supports-color": { "version": "5.3.0", "bundled": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -163,7 +163,7 @@ "version": "1.9.1", "bundled": true, "requires": { - "color-name": "1.1.3" + "color-name": "^1.1.1" } }, "color-name": { @@ -218,19 +218,19 @@ "version": "7.1.2", "bundled": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "has-ansi": { "version": "2.0.0", "bundled": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -245,8 +245,8 @@ "version": "1.0.6", "bundled": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -265,15 +265,15 @@ "version": "3.11.0", "bundled": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "minimatch": { "version": "3.0.4", "bundled": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -295,8 +295,8 @@ "version": "6.0.0", "bundled": true, "requires": { - "nativescript-intl": "3.0.0", - "reflect-metadata": "0.1.12" + "nativescript-intl": "^3.0.0", + "reflect-metadata": "^0.1.8" } }, "nativescript-intl": { @@ -311,7 +311,7 @@ "version": "1.4.0", "bundled": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "path-is-absolute": { @@ -330,19 +330,19 @@ "version": "1.0.0", "bundled": true, "requires": { - "colors": "1.2.1", - "pkginfo": "0.4.1", - "read": "1.0.7", - "revalidator": "0.1.8", - "utile": "0.3.0", - "winston": "2.1.1" + "colors": "^1.1.2", + "pkginfo": "0.x.x", + "read": "1.0.x", + "revalidator": "0.1.x", + "utile": "0.3.x", + "winston": "2.1.x" } }, "read": { "version": "1.0.7", "bundled": true, "requires": { - "mute-stream": "0.0.7" + "mute-stream": "~0.0.4" } }, "reflect-metadata": { @@ -353,7 +353,7 @@ "version": "1.6.0", "bundled": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "revalidator": { @@ -364,14 +364,14 @@ "version": "2.6.2", "bundled": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "rxjs": { "version": "6.0.0", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.9.0" } }, "semver": { @@ -390,7 +390,7 @@ "version": "3.0.1", "bundled": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -420,25 +420,25 @@ "version": "5.9.1", "bundled": true, "requires": { - "babel-code-frame": "6.26.0", - "builtin-modules": "1.1.1", - "chalk": "2.3.2", - "commander": "2.15.1", - "diff": "3.5.0", - "glob": "7.1.2", - "js-yaml": "3.11.0", - "minimatch": "3.0.4", - "resolve": "1.6.0", - "semver": "5.5.0", - "tslib": "1.9.0", - "tsutils": "2.26.0" + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.12.1" } }, "tsutils": { "version": "2.26.0", "bundled": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.8.1" } }, "typescript": { @@ -449,25 +449,25 @@ "version": "0.3.0", "bundled": true, "requires": { - "async": "0.9.2", - "deep-equal": "0.2.2", - "i": "0.3.6", - "mkdirp": "0.5.1", - "ncp": "1.0.1", - "rimraf": "2.6.2" + "async": "~0.9.0", + "deep-equal": "~0.2.1", + "i": "0.3.x", + "mkdirp": "0.x.x", + "ncp": "1.0.x", + "rimraf": "2.x.x" } }, "winston": { "version": "2.1.1", "bundled": true, "requires": { - "async": "1.0.0", - "colors": "1.0.3", - "cycle": "1.0.3", - "eyes": "0.1.8", - "isstream": "0.1.2", - "pkginfo": "0.3.1", - "stack-trace": "0.0.10" + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "pkginfo": "0.3.x", + "stack-trace": "0.0.x" }, "dependencies": { "async": { diff --git a/src/android/nativechat-web-chrome-client.d.ts b/src/android/nativechat-web-chrome-client.d.ts index 848c6d6..91cf8a3 100644 --- a/src/android/nativechat-web-chrome-client.d.ts +++ b/src/android/nativechat-web-chrome-client.d.ts @@ -1,5 +1,4 @@ export declare class NativeChatWebChromeClient extends android.webkit.WebChromeClient { onGeolocationPermissionsShowPrompt(origin: string, callback: android.webkit.GeolocationPermissions.ICallback): void; onShowFileChooser(webview: android.webkit.WebView, filePathCallback: android.webkit.ValueCallback, fileChooserParams: any): boolean; - shouldOverrideUrlLoading(webview: android.webkit.WebView, url: string): boolean; } diff --git a/src/android/nativechat-web-chrome-client.ts b/src/android/nativechat-web-chrome-client.ts index d8d58df..738933b 100644 --- a/src/android/nativechat-web-chrome-client.ts +++ b/src/android/nativechat-web-chrome-client.ts @@ -43,7 +43,6 @@ export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { try { const intent = fileChooserParams.createIntent(); - console.log(intent); context.startActivityForResult(intent, NativeChat.SELECT_FILE_RESULT_CODE); } catch (e) { context.uploadCallback = null; @@ -54,19 +53,4 @@ export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { return true; } - - shouldOverrideUrlLoading(webview: android.webkit.WebView, url: string): boolean { - if (url !== null && (url.startsWith("http://") || url.startsWith("https://"))) { - const context = application.android.currentContext; - - try { - context.startActivity(new android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(url))); - return true; - } catch (error) { - android.widget.Toast.makeText(context, 'Cannot open url', android.widget.Toast.LENGTH_LONG).show(); - } - } - - return false; - } } \ No newline at end of file diff --git a/src/android/nativechat-web-view-client.d.ts b/src/android/nativechat-web-view-client.d.ts new file mode 100644 index 0000000..11fb02d --- /dev/null +++ b/src/android/nativechat-web-view-client.d.ts @@ -0,0 +1,3 @@ +export declare class NativeChatWebViewClient extends android.webkit.WebViewClient { + shouldOverrideUrlLoading(webview: android.webkit.WebView, request: any): boolean; +} diff --git a/src/android/nativechat-web-view-client.ts b/src/android/nativechat-web-view-client.ts new file mode 100644 index 0000000..1f4e21a --- /dev/null +++ b/src/android/nativechat-web-view-client.ts @@ -0,0 +1,21 @@ +import * as application from 'tns-core-modules/application'; +import { Config } from '../nativechat'; + +export class NativeChatWebViewClient extends android.webkit.WebViewClient { + shouldOverrideUrlLoading(webview: android.webkit.WebView, request): boolean { // request: android.webkit.WebResourceRequest | string + const uri = request.getUrl ? request.getUrl() : android.net.Uri.parse(request); + const url = uri && uri.toString(); + const openInView = url && (url.startsWith(`https://${Config.webchatUrl}`) || url && url.startsWith(`http://${Config.webchatUrl}`)); + if (!openInView) { + const context = application.android.currentContext; + try { + context.startActivity(new android.content.Intent(android.content.Intent.ACTION_VIEW, uri)); + return true; + } catch (error) { + android.widget.Toast.makeText(context, 'Cannot open url', android.widget.Toast.LENGTH_LONG).show(); + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/nativechat.ts b/src/nativechat.ts index 089f2f6..3bfd212 100644 --- a/src/nativechat.ts +++ b/src/nativechat.ts @@ -2,13 +2,17 @@ import { GridLayout } from 'tns-core-modules/ui/layouts/grid-layout'; import { WebView } from 'tns-core-modules/ui/web-view'; import { isAndroid } from "tns-core-modules/platform" import { Observable, fromObject, EventData } from 'tns-core-modules/data/observable/observable'; - import * as builder from 'tns-core-modules/ui/builder' - +import * as builder from 'tns-core-modules/ui/builder' + import { NativeChatConfig } from './models'; import { NativeChatWebChromeClient } from './android/nativechat-web-chrome-client'; +import { NativeChatWebViewClient } from './android/nativechat-web-view-client'; + +export const Config = { + webchatUrl: 'webchat.nativechat.com', + webchatVersion: 'v1' +}; -const webchatUrl = 'https://webchat.nativechat.com/v1'; - export class NativeChat extends GridLayout { public static SELECT_FILE_RESULT_CODE = 100; public static REQUEST_LOCATION_CODE = 200; @@ -55,6 +59,7 @@ export class NativeChat extends GridLayout { settings.setDatabaseEnabled(true); webview.android.setWebChromeClient(new NativeChatWebChromeClient()); + webview.android.setWebViewClient(new NativeChatWebViewClient()); } } @@ -64,7 +69,7 @@ export class NativeChat extends GridLayout { private updateUrl(): void { if (this._config && this._config.botId && this._config.channelId && this._config.channelToken) { - let url = `${webchatUrl}?botId=${encodeURIComponent(this._config.botId)}`; + let url = `https://${Config.webchatUrl}/${Config.webchatVersion}?botId=${encodeURIComponent(this._config.botId)}`; url += `&channelId=${encodeURIComponent(this._config.channelId)}`; url += `&token=${encodeURIComponent(this._config.channelToken)}`; diff --git a/src/platforms/android/README.md b/src/platforms/android/README.md index ba1db50..f9a6719 100644 --- a/src/platforms/android/README.md +++ b/src/platforms/android/README.md @@ -1,9 +1,9 @@ # Android permissions and dependencies -* (Optional) Use AndroidManifest.xml to describe any permissions, features or other configuration specifics required or used by your plugin for Android. +* (Optional) Use AndroidManifest.xml to describe any permissions, features or other configuration specifics required or used by your plugin for Android. + 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. * (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) - [Read more about nativescript plugins](http://docs.nativescript.org/plugins/plugins) \ No newline at end of file From f994075afd0bdb9a4d02adb209b98a1257d0ebdd Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Wed, 27 Jun 2018 11:27:03 +0300 Subject: [PATCH 08/12] rename --- README.md | 6 +++--- demo/app/activity.android.ts | 10 +++++----- src/android/nativechat-web-chrome-client.ts | 10 +++++----- src/android/upload-file-activity.d.ts | 2 +- src/android/upload-file-activity.ts | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 01e9eec..7dcf59c 100644 --- a/README.md +++ b/README.md @@ -247,7 +247,7 @@ protected onActivityResult(requestCode: number, resultCode: number, data: androi } private upload(resultCode: number, data: android.content.Intent) { - if (this.uploadCallback === null) { + if (this.uploadFileCallback === null) { return; } @@ -263,8 +263,8 @@ private upload(resultCode: number, data: android.content.Intent) { } } - this.uploadCallback.onReceiveValue(uri); - this.uploadCallback = null; + this.uploadFileCallback.onReceiveValue(uri); + this.uploadFileCallback = null; } ``` diff --git a/demo/app/activity.android.ts b/demo/app/activity.android.ts index 0369567..e2f4567 100644 --- a/demo/app/activity.android.ts +++ b/demo/app/activity.android.ts @@ -8,7 +8,7 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo public geolocationCallback: android.webkit.GeolocationPermissions.ICallback; public geolocationOrigin: string; - public uploadCallback: android.webkit.ValueCallback; + public uploadFileCallback: android.webkit.ValueCallback; protected onCreate(savedInstanceState: android.os.Bundle): void { if (!this._callbacks) { @@ -16,7 +16,7 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo } this._callbacks.onCreate(this, savedInstanceState, super.onCreate); - this.uploadCallback = null; + this.uploadFileCallback = null; } protected onSaveInstanceState(outState: android.os.Bundle): void { @@ -61,7 +61,7 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo } private upload(resultCode: number, data: android.content.Intent) { - if (this.uploadCallback === null) { + if (this.uploadFileCallback === null) { return; } @@ -77,7 +77,7 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo } } - this.uploadCallback.onReceiveValue(uri); - this.uploadCallback = null; + this.uploadFileCallback.onReceiveValue(uri); + this.uploadFileCallback = null; } } diff --git a/src/android/nativechat-web-chrome-client.ts b/src/android/nativechat-web-chrome-client.ts index 738933b..45063ba 100644 --- a/src/android/nativechat-web-chrome-client.ts +++ b/src/android/nativechat-web-chrome-client.ts @@ -34,18 +34,18 @@ export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { ): boolean { const context = application.android.currentContext; - if (context.uploadCallback != null) { - context.uploadCallback.onReceiveValue(null); - context.uploadCallback = null; + if (context.uploadFileCallback != null) { + context.uploadFileCallback.onReceiveValue(null); + context.uploadFileCallback = null; } - context.uploadCallback = filePathCallback; + context.uploadFileCallback = filePathCallback; try { const intent = fileChooserParams.createIntent(); context.startActivityForResult(intent, NativeChat.SELECT_FILE_RESULT_CODE); } catch (e) { - context.uploadCallback = null; + context.uploadFileCallback = null; android.widget.Toast.makeText(context, 'Cannot open file chooser', android.widget.Toast.LENGTH_LONG).show(); return false; diff --git a/src/android/upload-file-activity.d.ts b/src/android/upload-file-activity.d.ts index fd31c90..8fe498c 100644 --- a/src/android/upload-file-activity.d.ts +++ b/src/android/upload-file-activity.d.ts @@ -1,3 +1,3 @@ export interface IUploadFileActivity { - uploadCallback: android.webkit.ValueCallback; + uploadFileCallback: android.webkit.ValueCallback; } diff --git a/src/android/upload-file-activity.ts b/src/android/upload-file-activity.ts index fd31c90..8fe498c 100644 --- a/src/android/upload-file-activity.ts +++ b/src/android/upload-file-activity.ts @@ -1,3 +1,3 @@ export interface IUploadFileActivity { - uploadCallback: android.webkit.ValueCallback; + uploadFileCallback: android.webkit.ValueCallback; } From 537d31b29075674b2a79a51522405380dd53fee6 Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Wed, 27 Jun 2018 12:59:13 +0300 Subject: [PATCH 09/12] rename --- demo/app/activity.android.ts | 8 ++++++-- src/android/nativechat-web-chrome-client.ts | 4 ++-- src/nativechat.ts | 4 +++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/demo/app/activity.android.ts b/demo/app/activity.android.ts index e2f4567..be450bc 100644 --- a/demo/app/activity.android.ts +++ b/demo/app/activity.android.ts @@ -1,6 +1,9 @@ import { setActivityCallbacks, AndroidActivityCallbacks } from "tns-core-modules/ui/frame"; import { NativeChat, IUploadFileActivity, IGeolocationActivity } from "@progress-nativechat/nativescript-nativechat"; +const ACCESS_FINE_LOCATION = (android as any).Manifest.permission.ACCESS_FINE_LOCATION; + + @JavaProxy("org.myApp.MainActivity") class Activity extends android.app.Activity implements IUploadFileActivity, IGeolocationActivity { private _callbacks: AndroidActivityCallbacks; @@ -42,8 +45,9 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); - if (requestCode === NativeChat.REQUEST_LOCATION_CODE) { - if (grantResults.length > 0 && grantResults[0] === android.content.pm.PackageManager.PERMISSION_GRANTED) { + if (requestCode === NativeChat.LOCATION_REQUEST_CODE) { + const index = permissions.indexOf(ACCESS_FINE_LOCATION); + if (index >= 0 && grantResults[index] === android.content.pm.PackageManager.PERMISSION_GRANTED) { if (this.geolocationCallback !== null && this.geolocationOrigin !== null) { this.geolocationCallback.invoke(this.geolocationOrigin, true, false); this.geolocationCallback = null; diff --git a/src/android/nativechat-web-chrome-client.ts b/src/android/nativechat-web-chrome-client.ts index 45063ba..f70081f 100644 --- a/src/android/nativechat-web-chrome-client.ts +++ b/src/android/nativechat-web-chrome-client.ts @@ -4,7 +4,7 @@ import { NativeChat } from '../nativechat'; const PERMISSION_GRANTED = android.content.pm.PackageManager.PERMISSION_GRANTED; const ACCESS_FINE_LOCATION = (android as any).Manifest.permission.ACCESS_FINE_LOCATION; -export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { +export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { onGeolocationPermissionsShowPrompt(origin: string, callback: android.webkit.GeolocationPermissions.ICallback) { const context = application.android.currentContext; @@ -16,7 +16,7 @@ export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { context.geolocationCallback = callback; context.geolocationOrigin = origin; try { - context.requestPermissions([ACCESS_FINE_LOCATION], NativeChat.REQUEST_LOCATION_CODE); + context.requestPermissions([ACCESS_FINE_LOCATION], NativeChat.LOCATION_REQUEST_CODE); } catch (e) { context.geolocationCallback = null; context.geolocationOrigin = null; diff --git a/src/nativechat.ts b/src/nativechat.ts index 3bfd212..0d468cc 100644 --- a/src/nativechat.ts +++ b/src/nativechat.ts @@ -15,7 +15,7 @@ export const Config = { export class NativeChat extends GridLayout { public static SELECT_FILE_RESULT_CODE = 100; - public static REQUEST_LOCATION_CODE = 200; + public static LOCATION_REQUEST_CODE = 200; private _webView: WebView; private _config: NativeChatConfig; @@ -55,8 +55,10 @@ export class NativeChat extends GridLayout { var settings = webview.android.getSettings(); settings.setDomStorageEnabled(true); settings.setDisplayZoomControls(false); + settings.setBuiltInZoomControls(false); settings.setAppCacheEnabled(true); settings.setDatabaseEnabled(true); + settings.setJavaScriptEnabled(true); webview.android.setWebChromeClient(new NativeChatWebChromeClient()); webview.android.setWebViewClient(new NativeChatWebViewClient()); From 43a1c34aa52734415d2a678ba8f5c572aab0512b Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Thu, 28 Jun 2018 09:46:32 +0300 Subject: [PATCH 10/12] refactor --- demo/app/activity.android.ts | 15 ++++++++++----- src/android/nativechat-web-chrome-client.ts | 2 +- src/android/nativechat-web-view-client.ts | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/demo/app/activity.android.ts b/demo/app/activity.android.ts index be450bc..8aac518 100644 --- a/demo/app/activity.android.ts +++ b/demo/app/activity.android.ts @@ -45,13 +45,18 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); - if (requestCode === NativeChat.LOCATION_REQUEST_CODE) { - const index = permissions.indexOf(ACCESS_FINE_LOCATION); - if (index >= 0 && grantResults[index] === android.content.pm.PackageManager.PERMISSION_GRANTED) { - if (this.geolocationCallback !== null && this.geolocationOrigin !== null) { - this.geolocationCallback.invoke(this.geolocationOrigin, true, false); + if (requestCode === NativeChat.LOCATION_REQUEST_CODE && + this.geolocationCallback && this.geolocationOrigin) { + + for (let index = 0; index < permissions.length; index++) { + if (permissions[index] === ACCESS_FINE_LOCATION) { + if (grantResults[index] === android.content.pm.PackageManager.PERMISSION_GRANTED) { + this.geolocationCallback.invoke(this.geolocationOrigin, true, true); + } + this.geolocationCallback = null; this.geolocationOrigin = null; + break; } } } diff --git a/src/android/nativechat-web-chrome-client.ts b/src/android/nativechat-web-chrome-client.ts index f70081f..c6eb018 100644 --- a/src/android/nativechat-web-chrome-client.ts +++ b/src/android/nativechat-web-chrome-client.ts @@ -23,7 +23,7 @@ export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { android.widget.Toast.makeText(context, 'Cannot request location permissions.', android.widget.Toast.LENGTH_LONG).show(); } } else { - callback.invoke(origin, true, false); + callback.invoke(origin, true, true); } } diff --git a/src/android/nativechat-web-view-client.ts b/src/android/nativechat-web-view-client.ts index 1f4e21a..636b3e2 100644 --- a/src/android/nativechat-web-view-client.ts +++ b/src/android/nativechat-web-view-client.ts @@ -5,7 +5,7 @@ export class NativeChatWebViewClient extends android.webkit.WebViewClient { shouldOverrideUrlLoading(webview: android.webkit.WebView, request): boolean { // request: android.webkit.WebResourceRequest | string const uri = request.getUrl ? request.getUrl() : android.net.Uri.parse(request); const url = uri && uri.toString(); - const openInView = url && (url.startsWith(`https://${Config.webchatUrl}`) || url && url.startsWith(`http://${Config.webchatUrl}`)); + const openInView = url && (url.startsWith(`https://${Config.webchatUrl}`) || url.startsWith(`http://${Config.webchatUrl}`)); if (!openInView) { const context = application.android.currentContext; try { @@ -14,7 +14,7 @@ export class NativeChatWebViewClient extends android.webkit.WebViewClient { } catch (error) { android.widget.Toast.makeText(context, 'Cannot open url', android.widget.Toast.LENGTH_LONG).show(); } - } + } return false; } From e6691a7fc6e886c7b81d000ae4fde2114538a5c6 Mon Sep 17 00:00:00 2001 From: Rositsa Topchiyska Date: Thu, 28 Jun 2018 11:53:31 +0300 Subject: [PATCH 11/12] Updated readme --- README.md | 62 +++++++++++++++++++++--------------- demo/app/activity.android.ts | 16 +++------- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 7dcf59c..b6b17dd 100644 --- a/README.md +++ b/README.md @@ -228,51 +228,61 @@ The *config* property should conform to the **NativeChatConfig** interface. | context | object | optional | A JSON object containing entities to be merged with the conversation context. They can be used as any other entity within the cognitive flow. Be careful to not override other entities used in the cognitive flow. | | userMessage | string | optional | Used to send a message on the user's behalf if the session is cleared. | -## Enable Functionality +## Enable Platform Functionality ### Android: File Picker - [extend application activity](https://docs.nativescript.org/angular/core-concepts/android-runtime/advanced-topics/extend-application-activity#extending-activity) - -Add the following code to the *onActivityResult* method: +You have to extend the application activity following [this](https://docs.nativescript.org/angular/core-concepts/android-runtime/advanced-topics/extend-application-activity#extending-activity) guide. Your activity should implement the *IUploadFileActivity* interface since the NativeChat plugin sets the `uploadFileCallback` activity property. Finally, add the following code to the *onActivityResult* method: ```typescript -import { NativeChat } from "@progress-nativechat/nativescript-nativechat"; +import { NativeChat, IUploadFileActivity } from "@progress-nativechat/nativescript-nativechat"; +const ACCESS_FINE_LOCATION = (android as any).Manifest.permission.ACCESS_FINE_LOCATION; + +@JavaProxy("org.myApp.MainActivity") +class Activity extends android.app.Activity implements IUploadFileActivity { + + public uploadFileCallback: android.webkit.ValueCallback; -protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { - this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult); - if (requestCode === NativeChat.SELECT_FILE_RESULT_CODE) { - this.upload(resultCode, data); + protected onCreate(savedInstanceState: android.os.Bundle): void { + if (!this._callbacks) { + setActivityCallbacks(this); + } + + this._callbacks.onCreate(this, savedInstanceState, super.onCreate); + this.uploadFileCallback = null; } -} -private upload(resultCode: number, data: android.content.Intent) { - if (this.uploadFileCallback === null) { - return; + protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { + this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult); + if (requestCode === NativeChat.SELECT_FILE_RESULT_CODE) { + this.upload(resultCode, data); + } } - let uri = null; - if (resultCode == android.app.Activity.RESULT_OK) { - if (data !== null) { - if (android.os.Build.VERSION.SDK_INT >= 21) { - uri = Array.create(android.net.Uri, 1); - uri[0] = android.net.Uri.parse(data.getDataString()); - } else { - uri = data.getData(); - } + private upload(resultCode: number, data: android.content.Intent) { + if (!this.uploadFileCallback) { + return; } + + let uri = null; + if (resultCode == android.app.Activity.RESULT_OK && data) { + uri = Array.create(android.net.Uri, 1); + uri[0] = android.net.Uri.parse(data.getDataString()); + } + + this.uploadFileCallback.onReceiveValue(uri); + this.uploadFileCallback = null; } - this.uploadFileCallback.onReceiveValue(uri); - this.uploadFileCallback = null; + // the rest of the activity methods... } ``` -### Android: Location Picker +The default value of `NativeChat.SELECT_FILE_RESULT_CODE` is `100`, but you can change it if there are collisions with another activity result code in your app. ### iOS: Location Picker -You have to requiest authorization from the user to use his location. Add *NSLocationWhenInUseUsageDescription* key in the *app/App_Resources/iOS/Info.plist* file. +You have to request authorization from the user to use his location. Add *NSLocationWhenInUseUsageDescription* key in the *app/App_Resources/iOS/Info.plist* file. ```xml diff --git a/demo/app/activity.android.ts b/demo/app/activity.android.ts index 8aac518..403611c 100644 --- a/demo/app/activity.android.ts +++ b/demo/app/activity.android.ts @@ -47,7 +47,7 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo if (requestCode === NativeChat.LOCATION_REQUEST_CODE && this.geolocationCallback && this.geolocationOrigin) { - + for (let index = 0; index < permissions.length; index++) { if (permissions[index] === ACCESS_FINE_LOCATION) { if (grantResults[index] === android.content.pm.PackageManager.PERMISSION_GRANTED) { @@ -70,20 +70,14 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo } private upload(resultCode: number, data: android.content.Intent) { - if (this.uploadFileCallback === null) { + if (!this.uploadFileCallback) { return; } let uri = null; - if (resultCode == android.app.Activity.RESULT_OK) { - if (data !== null) { - if (android.os.Build.VERSION.SDK_INT >= 21) { - uri = Array.create(android.net.Uri, 1); - uri[0] = android.net.Uri.parse(data.getDataString()); - } else { - uri = data.getData(); - } - } + if (resultCode == android.app.Activity.RESULT_OK && data) { + uri = Array.create(android.net.Uri, 1); + uri[0] = android.net.Uri.parse(data.getDataString()); } this.uploadFileCallback.onReceiveValue(uri); From 72980f80c447db3492f0aaa5e7988ccbb66f64e0 Mon Sep 17 00:00:00 2001 From: gugulete Date: Thu, 28 Jun 2018 13:30:29 +0300 Subject: [PATCH 12/12] rename --- README.md | 4 ++-- demo/app/activity.android.ts | 4 ++-- src/android/nativechat-web-chrome-client.ts | 4 ++-- src/nativechat.ts | 8 ++++++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b6b17dd..1b55442 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ class Activity extends android.app.Activity implements IUploadFileActivity { protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult); - if (requestCode === NativeChat.SELECT_FILE_RESULT_CODE) { + if (requestCode === NativeChat.platform.android.SELECT_FILE_RESULT_CODE) { this.upload(resultCode, data); } } @@ -278,7 +278,7 @@ class Activity extends android.app.Activity implements IUploadFileActivity { } ``` -The default value of `NativeChat.SELECT_FILE_RESULT_CODE` is `100`, but you can change it if there are collisions with another activity result code in your app. +The default value of `NativeChat.platform.android.SELECT_FILE_RESULT_CODE` is `100`, but you can change it if there are collisions with another activity result code in your app. ### iOS: Location Picker diff --git a/demo/app/activity.android.ts b/demo/app/activity.android.ts index 403611c..a3ee216 100644 --- a/demo/app/activity.android.ts +++ b/demo/app/activity.android.ts @@ -45,7 +45,7 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo public onRequestPermissionsResult(requestCode: number, permissions: Array, grantResults: Array): void { this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/); - if (requestCode === NativeChat.LOCATION_REQUEST_CODE && + if (requestCode === NativeChat.platform.android.LOCATION_REQUEST_CODE && this.geolocationCallback && this.geolocationOrigin) { for (let index = 0; index < permissions.length; index++) { @@ -64,7 +64,7 @@ class Activity extends android.app.Activity implements IUploadFileActivity, IGeo protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void { this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult); - if (requestCode === NativeChat.SELECT_FILE_RESULT_CODE) { + if (requestCode === NativeChat.platform.android.SELECT_FILE_RESULT_CODE) { this.upload(resultCode, data); } } diff --git a/src/android/nativechat-web-chrome-client.ts b/src/android/nativechat-web-chrome-client.ts index c6eb018..026212a 100644 --- a/src/android/nativechat-web-chrome-client.ts +++ b/src/android/nativechat-web-chrome-client.ts @@ -16,7 +16,7 @@ export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { context.geolocationCallback = callback; context.geolocationOrigin = origin; try { - context.requestPermissions([ACCESS_FINE_LOCATION], NativeChat.LOCATION_REQUEST_CODE); + context.requestPermissions([ACCESS_FINE_LOCATION], NativeChat.platform.android.LOCATION_REQUEST_CODE); } catch (e) { context.geolocationCallback = null; context.geolocationOrigin = null; @@ -43,7 +43,7 @@ export class NativeChatWebChromeClient extends android.webkit.WebChromeClient { try { const intent = fileChooserParams.createIntent(); - context.startActivityForResult(intent, NativeChat.SELECT_FILE_RESULT_CODE); + context.startActivityForResult(intent, NativeChat.platform.android.SELECT_FILE_RESULT_CODE); } catch (e) { context.uploadFileCallback = null; android.widget.Toast.makeText(context, 'Cannot open file chooser', android.widget.Toast.LENGTH_LONG).show(); diff --git a/src/nativechat.ts b/src/nativechat.ts index 0d468cc..4999c81 100644 --- a/src/nativechat.ts +++ b/src/nativechat.ts @@ -14,8 +14,12 @@ export const Config = { }; export class NativeChat extends GridLayout { - public static SELECT_FILE_RESULT_CODE = 100; - public static LOCATION_REQUEST_CODE = 200; + public static platform = { + android: { + SELECT_FILE_RESULT_CODE: 100, + LOCATION_REQUEST_CODE: 200 + } + }; private _webView: WebView; private _config: NativeChatConfig;