Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ publish/src
publish/package
demo/report/report.html
demo/report/stats.json
src/platforms/android/nativescript_nativechat.aar
88 changes: 77 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
<Page loaded="pageLoaded" xmlns:nativechat="@progress-nativechat/nativescript-nativechat">
<nativechat:NativeChat config="{{ nativeChatConfig }}"/>
</Page>
```

```javascript
exports.pageLoaded = function (args) {
var page = args.object;
Expand All @@ -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');
Expand Down Expand Up @@ -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
<Page
Expand All @@ -87,6 +84,7 @@ exports.pageLoaded = function (args) {
<nativechat:NativeChat config="{{ nativeChatConfig }}"/>
</Page>
```

```typescript
import { EventData, fromObject } from 'tns-core-modules/data/observable';
import { Page } from 'tns-core-modules/ui/page';
Expand All @@ -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';
Expand Down Expand Up @@ -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 |
Expand All @@ -230,6 +228,74 @@ 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 Platform Functionality

### Android: File Picker

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, 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<android.net.Uri>;

protected onCreate(savedInstanceState: android.os.Bundle): void {
if (!this._callbacks) {
setActivityCallbacks(this);
}

this._callbacks.onCreate(this, savedInstanceState, super.onCreate);
this.uploadFileCallback = null;
}

protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void {
this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult);
if (requestCode === NativeChat.platform.android.SELECT_FILE_RESULT_CODE) {
this.upload(resultCode, data);
}
}

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;
}

// the rest of the activity methods...
}
```

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

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
...
<key>NSLocationWhenInUseUsageDescription</key>
<string>Can I use your location?</string>
</dict>
</plist>
```

## License

Apache License Version 2.0, January 2004
6 changes: 4 additions & 2 deletions demo/app/App_Resources/Android/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<application
android:name="com.tns.NativeScriptApplication"
Expand All @@ -26,10 +27,11 @@
android:theme="@style/AppTheme">

<activity
android:name="com.tns.NativeScriptActivity"
android:name="org.myApp.MainActivity"
android:label="@string/title_activity_kimera"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/LaunchScreenTheme">
android:theme="@style/LaunchScreenTheme"
android:windowSoftInputMode="adjustResize">

<meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />

Expand Down
2 changes: 2 additions & 0 deletions demo/app/App_Resources/iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Can I use your location?</string>
</dict>
</plist>
86 changes: 86 additions & 0 deletions demo/app/activity.android.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
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;

public geolocationCallback: android.webkit.GeolocationPermissions.ICallback;
public geolocationOrigin: string;

public uploadFileCallback: android.webkit.ValueCallback<android.net.Uri>;

protected onCreate(savedInstanceState: android.os.Bundle): void {
if (!this._callbacks) {
setActivityCallbacks(this);
}

this._callbacks.onCreate(this, savedInstanceState, super.onCreate);
this.uploadFileCallback = null;
}

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<String>, grantResults: Array<number>): void {
this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined /*TODO: Enable if needed*/);

if (requestCode === NativeChat.platform.android.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;
}
}
}
}

protected onActivityResult(requestCode: number, resultCode: number, data: android.content.Intent): void {
this._callbacks.onActivityResult(this, requestCode, resultCode, data, super.onActivityResult);
if (requestCode === NativeChat.platform.android.SELECT_FILE_RESULT_CODE) {
this.upload(resultCode, data);
}
}

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;
}
}
Loading