diff --git a/README.md b/README.md
index 7c70a39d..08b1ae89 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@
- [@nativescript/fingerprint-auth](packages/fingerprint-auth/README.md)
- [@nativescript/geolocation](packages/geolocation/README.md)
- [@nativescript/google-maps](packages/google-maps/README.md)
+- [@nativescript/google-maps-utils](packages/google-maps-utils/README.md)
- [@nativescript/google-mobile-ads](packages/google-mobile-ads/README.md)
- [@nativescript/google-signin](packages/google-signin/README.md)
- [@nativescript/haptics](packages/haptics/README.md)
diff --git a/apps/demo-angular/src/plugin-demos/google-maps-utils.component.html b/apps/demo-angular/src/plugin-demos/google-maps-utils.component.html
new file mode 100644
index 00000000..56634035
--- /dev/null
+++ b/apps/demo-angular/src/plugin-demos/google-maps-utils.component.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/apps/demo-angular/src/plugin-demos/google-maps-utils.component.ts b/apps/demo-angular/src/plugin-demos/google-maps-utils.component.ts
new file mode 100644
index 00000000..3ae88b2b
--- /dev/null
+++ b/apps/demo-angular/src/plugin-demos/google-maps-utils.component.ts
@@ -0,0 +1,19 @@
+import { Component, NgZone } from '@angular/core';
+import { DemoSharedGoogleMapsUtils } from '@demo/shared';
+import { } from '@nativescript/google-maps-utils';
+
+@Component({
+ selector: 'demo-google-maps-utils',
+ templateUrl: 'google-maps-utils.component.html',
+})
+export class GoogleMapsUtilsComponent {
+
+ demoShared: DemoSharedGoogleMapsUtils;
+
+ constructor(private _ngZone: NgZone) {}
+
+ ngOnInit() {
+ this.demoShared = new DemoSharedGoogleMapsUtils();
+ }
+
+}
\ No newline at end of file
diff --git a/apps/demo-angular/src/plugin-demos/google-maps-utils.module.ts b/apps/demo-angular/src/plugin-demos/google-maps-utils.module.ts
new file mode 100644
index 00000000..1a219672
--- /dev/null
+++ b/apps/demo-angular/src/plugin-demos/google-maps-utils.module.ts
@@ -0,0 +1,10 @@
+import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
+import { NativeScriptCommonModule, NativeScriptRouterModule } from '@nativescript/angular';
+import { GoogleMapsUtilsComponent } from './google-maps-utils.component';
+
+@NgModule({
+ imports: [NativeScriptCommonModule, NativeScriptRouterModule.forChild([{ path: '', component: GoogleMapsUtilsComponent }])],
+ declarations: [GoogleMapsUtilsComponent],
+ schemas: [ NO_ERRORS_SCHEMA]
+})
+export class GoogleMapsUtilsModule {}
diff --git a/apps/demo/package.json b/apps/demo/package.json
index 655c9922..17107122 100644
--- a/apps/demo/package.json
+++ b/apps/demo/package.json
@@ -4,6 +4,9 @@
"license": "SEE LICENSE IN ",
"repository": "",
"dependencies": {
+ "@nativescript/google-maps": "file:../../packages/google-maps",
+ "@nativescript/google-maps-utils": "file:../../packages/google-maps-utils",
+ "@nativescript/jetpack-compose": "file:../../packages/jetpack-compose",
"@nativescript/core": "*",
"@nativescript/camera": "file:../../packages/camera",
"@nativescript/animated-circle": "file:../../packages/animated-circle",
@@ -23,7 +26,6 @@
"@nativescript/facebook": "file:../../packages/facebook",
"@nativescript/fingerprint-auth": "file:../../packages/fingerprint-auth",
"@nativescript/geolocation": "file:../../packages/geolocation",
- "@nativescript/google-maps": "file:../../packages/google-maps",
"@nativescript/google-signin": "file:../../packages/google-signin",
"@nativescript/haptics": "file:../../packages/haptics",
"@nativescript/imagepicker": "file:../../packages/imagepicker",
diff --git a/apps/demo/src/main-page.xml b/apps/demo/src/main-page.xml
index 8bcd8a0b..fbbf575e 100644
--- a/apps/demo/src/main-page.xml
+++ b/apps/demo/src/main-page.xml
@@ -24,6 +24,7 @@
+
diff --git a/apps/demo/src/plugin-demos/google-maps-utils.ts b/apps/demo/src/plugin-demos/google-maps-utils.ts
new file mode 100644
index 00000000..b60e6307
--- /dev/null
+++ b/apps/demo/src/plugin-demos/google-maps-utils.ts
@@ -0,0 +1,12 @@
+import { Observable, EventData, Page } from '@nativescript/core';
+import { DemoSharedGoogleMapsUtils } from '@demo/shared';
+import { } from '@nativescript/google-maps-utils';
+
+export function navigatingTo(args: EventData) {
+ const page = args.object;
+ page.bindingContext = new DemoModel();
+}
+
+export class DemoModel extends DemoSharedGoogleMapsUtils {
+
+}
diff --git a/apps/demo/src/plugin-demos/google-maps-utils.xml b/apps/demo/src/plugin-demos/google-maps-utils.xml
new file mode 100644
index 00000000..65a33ef6
--- /dev/null
+++ b/apps/demo/src/plugin-demos/google-maps-utils.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/animated-circle/index.android.ts b/packages/animated-circle/index.android.ts
index 0cf9acb8..0a6d63d3 100644
--- a/packages/animated-circle/index.android.ts
+++ b/packages/animated-circle/index.android.ts
@@ -48,7 +48,7 @@ export class AnimatedCircle extends AnimatedCircleCommon {
this.android.setInnerContourSize(0);
this.android.setText(this.text);
this.android.setTextColor(this._textColor.argb);
- if(this._textSize !== 0){
+ if (this._textSize !== 0) {
this.android.setTextSize(this._textSize);
}
if (this.animated) {
@@ -329,8 +329,8 @@ export class AnimatedCircle extends AnimatedCircleCommon {
}
}
- private getNumber(value: number | string){
- return typeof value === 'string' ? parseInt(value) : value
+ private getNumber(value: number | string) {
+ return typeof value === 'string' ? parseInt(value) : value;
}
}
diff --git a/packages/background-http/index.d.ts b/packages/background-http/index.d.ts
index 964a8df8..8d41226c 100644
--- a/packages/background-http/index.d.ts
+++ b/packages/background-http/index.d.ts
@@ -1,4 +1,4 @@
-import { EventData } from "@nativescript/core";
+import { EventData } from '@nativescript/core';
export function init();
@@ -12,248 +12,243 @@ export function session(id: string): Session;
* Provides error information for error notifications.
*/
export interface ErrorEventData extends EventData {
- /**
- * Provides the underlying error. The value is platform specific.
- */
- error: any /*NSError | java.lang.Exception*/;
- /** HTTP response code if response object is present, otherwise -1 */
- responseCode: number;
-
- // The response from server
- response: any; // net.gotev.uploadservice.ServerResponse
+ /**
+ * Provides the underlying error. The value is platform specific.
+ */
+ error: any /*NSError | java.lang.Exception*/;
+ /** HTTP response code if response object is present, otherwise -1 */
+ responseCode: number;
+
+ // The response from server
+ response: any; // net.gotev.uploadservice.ServerResponse
}
/**
* Provides the current and total bytes of long running transfer tasks.
*/
export interface ProgressEventData extends EventData {
- /**
- * The bytes transfered so far.
- */
- currentBytes: number;
-
- /**
- * The expected bytes to transfer.
- */
- totalBytes: number;
+ /**
+ * The bytes transfered so far.
+ */
+ currentBytes: number;
+
+ /**
+ * The expected bytes to transfer.
+ */
+ totalBytes: number;
}
/**
* Provides the server response.
*/
export interface ResultEventData extends EventData {
- /**
- * The string response of the server.
- */
- data: string;
- /** HTTP response code if response object is present, otherwise -1 */
- responseCode: number;
+ /**
+ * The string response of the server.
+ */
+ data: string;
+ /** HTTP response code if response object is present, otherwise -1 */
+ responseCode: number;
}
export interface CompleteEventData extends EventData {
- /** HTTP response code if response object is present, otherwise -1 */
- responseCode: number;
- /** Currently available for Android only */
- response?: any; // net.gotev.uploadservice.ServerResponse
+ /** HTTP response code if response object is present, otherwise -1 */
+ responseCode: number;
+ /** Currently available for Android only */
+ response?: any; // net.gotev.uploadservice.ServerResponse
}
/**
* Encapsulates some information for background http transfers.
*/
export interface Task {
- /**
- * Get the description of the task, that was provided during the task creation.
- */
- description: string;
-
- /**
- * Gets the current count of uploaded bytes. (read-only)
- */
- upload: number;
-
- /**
- * Gets the expected total count of bytes to upload. (read-only)
- */
- totalUpload: number;
-
- /**
- * Gets the status of the background upload task.
- * Possible states: "panding" | "uploading" | "error" | "complete".
- * (read-only)
- */
- status: string;
-
- /**
- * Cancel the Upload Task.
- */
- cancel(): void;
- /**
- * Subscribe for a general event.
- * @param event The name of the event to subscribe for.
- * @param handler The handler called when the event occure.
- * @event
- */
- on(event: string, handler: (e: EventData) => void): void;
-
- /**
- * Subscribe for error notifications.
- * @param event
- * @param handler A handler that will receive the error details
- * @event
- */
- on(event: "error", handler: (e: ErrorEventData) => void): void;
-
- /**
- * Subscribe for progress notifications.
- * @param event
- * @param handler A handler that will receive a progress event with the current and expected total bytes
- * @event
- */
- on(event: "progress", handler: (e: ProgressEventData) => void): void;
-
- /**
- * Upon successful upload provides the server response.
- * @param event
- * @param handler A handler that will receive the response event.
- * @event
- */
- on(event: "responded", handler: (e: ResultEventData) => void): void;
-
- /**
- * Subscribe for the success notification.
- * @param event
- * @param handler A function that will be called with general event data upon successful completion
- * @event
- */
- on(event: "complete", handler: (e: CompleteEventData) => void): void;
+ /**
+ * Get the description of the task, that was provided during the task creation.
+ */
+ description: string;
+
+ /**
+ * Gets the current count of uploaded bytes. (read-only)
+ */
+ upload: number;
+
+ /**
+ * Gets the expected total count of bytes to upload. (read-only)
+ */
+ totalUpload: number;
+
+ /**
+ * Gets the status of the background upload task.
+ * Possible states: "panding" | "uploading" | "error" | "complete".
+ * (read-only)
+ */
+ status: string;
+
+ /**
+ * Cancel the Upload Task.
+ */
+ cancel(): void;
+ /**
+ * Subscribe for a general event.
+ * @param event The name of the event to subscribe for.
+ * @param handler The handler called when the event occure.
+ * @event
+ */
+ on(event: string, handler: (e: EventData) => void): void;
+
+ /**
+ * Subscribe for error notifications.
+ * @param event
+ * @param handler A handler that will receive the error details
+ * @event
+ */
+ on(event: 'error', handler: (e: ErrorEventData) => void): void;
+
+ /**
+ * Subscribe for progress notifications.
+ * @param event
+ * @param handler A handler that will receive a progress event with the current and expected total bytes
+ * @event
+ */
+ on(event: 'progress', handler: (e: ProgressEventData) => void): void;
+
+ /**
+ * Upon successful upload provides the server response.
+ * @param event
+ * @param handler A handler that will receive the response event.
+ * @event
+ */
+ on(event: 'responded', handler: (e: ResultEventData) => void): void;
+
+ /**
+ * Subscribe for the success notification.
+ * @param event
+ * @param handler A function that will be called with general event data upon successful completion
+ * @event
+ */
+ on(event: 'complete', handler: (e: CompleteEventData) => void): void;
}
/**
* Groups background http tasks in sessions, used to initiate background transfers.
*/
export interface Session {
- /**
- * Initiate a new background file upload task.
- * @param fileUri A file path to upload.
- * @param options Options for the upload, sets uri, headers, task description etc.
- */
- uploadFile(fileUri: string, options: Request): Task;
- multipartUpload(params: Array, options: Request): Task;
-
+ /**
+ * Initiate a new background file upload task.
+ * @param fileUri A file path to upload.
+ * @param options Options for the upload, sets uri, headers, task description etc.
+ */
+ uploadFile(fileUri: string, options: Request): Task;
+ multipartUpload(params: Array, options: Request): Task;
}
/**
* Encapsulates the information required to initiate new background transfers.
*/
export interface Request {
- /**
- * Gets or sets the request url.
- */
- url: string;
-
- /**
- * Gets or set the HTTP method.
- * By default 'GET' will be used.
- */
- method?: string;
-
- /**
- * Specify additional HTTP headers.
- */
- headers?: {};
-
- /**
- * Use this to help you identify the task.
- * Sets the task's description property.
- * You can store serialized JSON object.
- */
- description: string;
-
- /**
- * iOS only. Sets NSMutableURLRequest.timeoutInterval value in seconds (s)
- */
- timeout?: number
+ /**
+ * Gets or sets the request url.
+ */
+ url: string;
- /**
- * Use utf8 encode in requests
- */
- utf8?: boolean;
+ /**
+ * Gets or set the HTTP method.
+ * By default 'GET' will be used.
+ */
+ method?: string;
- /*
- * Use this to set the on progress title shown in the Android notifications center.
- */
+ /**
+ * Specify additional HTTP headers.
+ */
+ headers?: {};
- androidNotificationOnProgressTitle?: string;
+ /**
+ * Use this to help you identify the task.
+ * Sets the task's description property.
+ * You can store serialized JSON object.
+ */
+ description: string;
- /*
- * Use this to set the on progress message shown in the Android notifications center.
- */
+ /**
+ * iOS only. Sets NSMutableURLRequest.timeoutInterval value in seconds (s)
+ */
+ timeout?: number;
- androidNotificationOnProgressMessage?: string;
+ /**
+ * Use utf8 encode in requests
+ */
+ utf8?: boolean;
+ /*
+ * Use this to set the on progress title shown in the Android notifications center.
+ */
- /*
- * Use this to set the on complete title shown in the Android notifications center.
- */
+ androidNotificationOnProgressTitle?: string;
- androidNotificationOnCompleteTitle?: string;
+ /*
+ * Use this to set the on progress message shown in the Android notifications center.
+ */
- /*
- * Use this to set the on complete message shown in the Android notifications center.
- */
+ androidNotificationOnProgressMessage?: string;
- androidNotificationOnCompleteMessage?: string;
+ /*
+ * Use this to set the on complete title shown in the Android notifications center.
+ */
+ androidNotificationOnCompleteTitle?: string;
- /*
- * Use this to set the on error title shown in the Android notifications center.
- */
+ /*
+ * Use this to set the on complete message shown in the Android notifications center.
+ */
- androidNotificationOnErrorTitle?: string;
+ androidNotificationOnCompleteMessage?: string;
- /*
- * Use this to set the on error message shown in the Android notifications center.
- */
+ /*
+ * Use this to set the on error title shown in the Android notifications center.
+ */
- androidNotificationOnErrorMessage?: string;
+ androidNotificationOnErrorTitle?: string;
+ /*
+ * Use this to set the on error message shown in the Android notifications center.
+ */
- /*
- * Use this to set the on cancelled title shown in the Android notifications center.
- */
+ androidNotificationOnErrorMessage?: string;
- androidNotificationOnCancelledTitle?: string;
+ /*
+ * Use this to set the on cancelled title shown in the Android notifications center.
+ */
- /*
- * Use this to set the on cancelled message shown in the Android notifications center.
- */
+ androidNotificationOnCancelledTitle?: string;
- androidNotificationOnCancelledMessage?: string;
+ /*
+ * Use this to set the on cancelled message shown in the Android notifications center.
+ */
+ androidNotificationOnCancelledMessage?: string;
- /*
- * Use this to set if files should be deleted automatically after upload
- */
- androidAutoDeleteAfterUpload?: boolean;
+ /*
+ * Use this to set if files should be deleted automatically after upload
+ */
+ androidAutoDeleteAfterUpload?: boolean;
- /*
- * Use this to set the maximum retry count. The default retry count is 0
- * https://github.com/gotev/android-upload-service/wiki/Recipes#backoff
- */
- androidMaxRetries?: number;
+ /*
+ * Use this to set the maximum retry count. The default retry count is 0
+ * https://github.com/gotev/android-upload-service/wiki/Recipes#backoff
+ */
+ androidMaxRetries?: number;
- /*
- * Use this to set if notifications should be cleared automatically upon upload completion
- */
- androidAutoClearNotification?: boolean;
+ /*
+ * Use this to set if notifications should be cleared automatically upon upload completion
+ */
+ androidAutoClearNotification?: boolean;
- /*
- * Use this to set if a ringtone should be played upon upload completion
- */
- androidRingToneEnabled?: boolean;
+ /*
+ * Use this to set if a ringtone should be played upon upload completion
+ */
+ androidRingToneEnabled?: boolean;
- /*
- * Use this to set the channel ID for the notifications
- */
- androidNotificationChannelID?: string;
+ /*
+ * Use this to set the channel ID for the notifications
+ */
+ androidNotificationChannelID?: string;
}
diff --git a/packages/background-http/index.ios.ts b/packages/background-http/index.ios.ts
index 53a90663..e4b01d55 100644
--- a/packages/background-http/index.ios.ts
+++ b/packages/background-http/index.ios.ts
@@ -1,388 +1,380 @@
-import { knownFolders, Observable } from "@nativescript/core";
-import { CompleteEventData, ErrorEventData, ProgressEventData, Request as IRequest, ResultEventData } from ".";
+import { knownFolders, Observable } from '@nativescript/core';
+import { CompleteEventData, ErrorEventData, ProgressEventData, Request as IRequest, ResultEventData } from '.';
const main_queue = dispatch_get_current_queue();
let zonedOnProgress = null;
let zonedOnError = null;
-export function init(){}
+export function init() {}
function onProgress(nsSession, nsTask, sent, expectedTotal) {
- const task = Task.getTask(nsSession, nsTask);
- task.notifyPropertyChange("upload", task.upload);
- task.notifyPropertyChange("totalUpload", task.totalUpload);
- task.notify({
- eventName: "progress",
- object: task,
- currentBytes: sent,
- totalBytes: expectedTotal
- });
+ const task = Task.getTask(nsSession, nsTask);
+ task.notifyPropertyChange('upload', task.upload);
+ task.notifyPropertyChange('totalUpload', task.totalUpload);
+ task.notify({
+ eventName: 'progress',
+ object: task,
+ currentBytes: sent,
+ totalBytes: expectedTotal,
+ });
}
function onError(session, nsTask, error) {
- const task = Task.getTask(session, nsTask);
- if (task._fileToCleanup) {
- NSFileManager.defaultManager.removeItemAtPathError(task._fileToCleanup);
- }
- const response = nsTask && nsTask.performSelector("response");
- if (error) {
- task.notifyPropertyChange("status", task.status);
- task.notify({
- eventName: "error",
- object: task,
- error,
- responseCode: response ? response.statusCode : -1,
- response
- });
- } else {
- task.notifyPropertyChange("upload", task.upload);
- task.notifyPropertyChange("totalUpload", task.totalUpload);
- task.notify({
- eventName: "progress",
- object: task,
- currentBytes: nsTask.countOfBytesSent,
- totalBytes: nsTask.countOfBytesExpectedToSend
- });
- task.notify({
- eventName: "complete",
- object: task,
- responseCode: response ? response.statusCode : -1,
- response
- });
-
- Task._tasks.delete(nsTask);
- }
+ const task = Task.getTask(session, nsTask);
+ if (task._fileToCleanup) {
+ NSFileManager.defaultManager.removeItemAtPathError(task._fileToCleanup);
+ }
+ const response = nsTask && nsTask.performSelector('response');
+ if (error) {
+ task.notifyPropertyChange('status', task.status);
+ task.notify({
+ eventName: 'error',
+ object: task,
+ error,
+ responseCode: response ? response.statusCode : -1,
+ response,
+ });
+ } else {
+ task.notifyPropertyChange('upload', task.upload);
+ task.notifyPropertyChange('totalUpload', task.totalUpload);
+ task.notify({
+ eventName: 'progress',
+ object: task,
+ currentBytes: nsTask.countOfBytesSent,
+ totalBytes: nsTask.countOfBytesExpectedToSend,
+ });
+ task.notify({
+ eventName: 'complete',
+ object: task,
+ responseCode: response ? response.statusCode : -1,
+ response,
+ });
+
+ Task._tasks.delete(nsTask);
+ }
}
@NativeClass()
class BackgroundUploadDelegate extends NSObject implements NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
-
- static ObjCProtocols = [NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate];
-
- // NSURLSessionDelegate
- URLSessionDidBecomeInvalidWithError(session, error) {
- }
-
- URLSessionDidReceiveChallengeCompletionHandler(session, challenge, comlpetionHandler) {
- const disposition = null;
- const credential = null;
- comlpetionHandler(disposition, credential);
- }
-
- URLSessionDidFinishEventsForBackgroundURLSession(session) {
- }
-
- // NSURLSessionTaskDelegate
- URLSessionTaskDidCompleteWithError(session: NSURLSession, nsTask: NSURLSessionTask, error: NSError) {
- dispatch_async(main_queue, () => {
- zonedOnError(session, nsTask, error);
- });
- }
-
- URLSessionTaskDidReceiveChallengeCompletionHandler(session, task, challenge, completionHandler) {
- const disposition = null;
- const credential = null;
- completionHandler(disposition, credential);
- }
-
- URLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedToSend(nsSession: NSURLSession, nsTask: NSURLSessionTask, data, sent: number, expectedTotal: number) {
- dispatch_async(main_queue, () => {
- zonedOnProgress(nsSession, nsTask, sent, expectedTotal);
- });
- }
-
- URLSessionTaskNeedNewBodyStream(session, task, need) {
- }
-
- URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler(session, task, redirect, request, completionHandler) {
- completionHandler(request);
- }
-
- // NSURLSessionDataDelegate
- URLSessionDataTaskDidReceiveResponseCompletionHandler(session, dataTask, response, completionHandler) {
- const disposition = null;
- completionHandler(disposition);
- }
-
- URLSessionDataTaskDidBecomeDownloadTask(session, dataTask, downloadTask) {
- }
-
- URLSessionDataTaskDidReceiveData(session: NSURLSession, dataTask: NSURLSessionDataTask, data: NSData) {
- dispatch_async(main_queue, () => {
- // we have a response in the data...
- const jsTask = Task.getTask(session, dataTask);
- const jsonString = NSString.alloc().initWithDataEncoding(data, NSUTF8StringEncoding);
-
- jsTask.notify({
- eventName: "responded",
- object: jsTask,
- data: jsonString.toString(),
- responseCode: dataTask && dataTask.response ? (dataTask.response).statusCode : -1
- });
- });
- }
-
- URLSessionDataTaskWillCacheResponseCompletionHandler() {
- }
-
- // NSURLSessionDownloadDelegate
- URLSessionDownloadTaskDidResumeAtOffsetExpectedTotalBytes(session, task, offset, expects) {
- }
-
- URLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesExpectedToWrite(session, task, data, written, expected) {
- }
-
- URLSessionDownloadTaskDidFinishDownloadingToURL(session, task, url) {
- }
+ static ObjCProtocols = [NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate];
+
+ // NSURLSessionDelegate
+ URLSessionDidBecomeInvalidWithError(session, error) {}
+
+ URLSessionDidReceiveChallengeCompletionHandler(session, challenge, comlpetionHandler) {
+ const disposition = null;
+ const credential = null;
+ comlpetionHandler(disposition, credential);
+ }
+
+ URLSessionDidFinishEventsForBackgroundURLSession(session) {}
+
+ // NSURLSessionTaskDelegate
+ URLSessionTaskDidCompleteWithError(session: NSURLSession, nsTask: NSURLSessionTask, error: NSError) {
+ dispatch_async(main_queue, () => {
+ zonedOnError(session, nsTask, error);
+ });
+ }
+
+ URLSessionTaskDidReceiveChallengeCompletionHandler(session, task, challenge, completionHandler) {
+ const disposition = null;
+ const credential = null;
+ completionHandler(disposition, credential);
+ }
+
+ URLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedToSend(nsSession: NSURLSession, nsTask: NSURLSessionTask, data, sent: number, expectedTotal: number) {
+ dispatch_async(main_queue, () => {
+ zonedOnProgress(nsSession, nsTask, sent, expectedTotal);
+ });
+ }
+
+ URLSessionTaskNeedNewBodyStream(session, task, need) {}
+
+ URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler(session, task, redirect, request, completionHandler) {
+ completionHandler(request);
+ }
+
+ // NSURLSessionDataDelegate
+ URLSessionDataTaskDidReceiveResponseCompletionHandler(session, dataTask, response, completionHandler) {
+ const disposition = null;
+ completionHandler(disposition);
+ }
+
+ URLSessionDataTaskDidBecomeDownloadTask(session, dataTask, downloadTask) {}
+
+ URLSessionDataTaskDidReceiveData(session: NSURLSession, dataTask: NSURLSessionDataTask, data: NSData) {
+ dispatch_async(main_queue, () => {
+ // we have a response in the data...
+ const jsTask = Task.getTask(session, dataTask);
+ const jsonString = NSString.alloc().initWithDataEncoding(data, NSUTF8StringEncoding);
+
+ jsTask.notify({
+ eventName: 'responded',
+ object: jsTask,
+ data: jsonString.toString(),
+ responseCode: dataTask && dataTask.response ? (dataTask.response).statusCode : -1,
+ });
+ });
+ }
+
+ URLSessionDataTaskWillCacheResponseCompletionHandler() {}
+
+ // NSURLSessionDownloadDelegate
+ URLSessionDownloadTaskDidResumeAtOffsetExpectedTotalBytes(session, task, offset, expects) {}
+
+ URLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesExpectedToWrite(session, task, data, written, expected) {}
+
+ URLSessionDownloadTaskDidFinishDownloadingToURL(session, task, url) {}
}
class Session implements Session {
- // TODO: Create a mechanism to clean sessions from the cache that have all their tasks completed, canceled or errored out.
- private static _sessions: { [id: string]: Session } = {};
-
- private _session: NSURLSession;
-
- constructor(id: string) {
- const delegate = BackgroundUploadDelegate.alloc().init();
- const configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(id);
- this._session = NSURLSession.sessionWithConfigurationDelegateDelegateQueue(configuration, delegate, null);
- zonedOnProgress = global.zonedCallback(onProgress);
- zonedOnError = global.zonedCallback(onError);
- }
-
- get ios(): any {
- return this._session;
- }
-
-
- public uploadFile(fileUri: string, options: IRequest): Task {
- if (!fileUri) {
- throw new Error("File must be provided.");
- }
-
- const url = NSURL.URLWithString(options.url);
- const request = NSMutableURLRequest.requestWithURL(url);
-
- const headers = options.headers;
- if (headers) {
- for (let header in headers) {
- const value = headers[header];
- if (value !== null && value !== void 0) {
- request.setValueForHTTPHeaderField(value.toString(), header);
- }
- }
- }
-
- if (options.method) {
- request.HTTPMethod = options.method;
- }
-
- if (options.timeout) {
- request.timeoutInterval = options.timeout;
+ // TODO: Create a mechanism to clean sessions from the cache that have all their tasks completed, canceled or errored out.
+ private static _sessions: { [id: string]: Session } = {};
+
+ private _session: NSURLSession;
+
+ constructor(id: string) {
+ const delegate = BackgroundUploadDelegate.alloc().init();
+ const configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(id);
+ this._session = NSURLSession.sessionWithConfigurationDelegateDelegateQueue(configuration, delegate, null);
+ zonedOnProgress = global.zonedCallback(onProgress);
+ zonedOnError = global.zonedCallback(onError);
+ }
+
+ get ios(): any {
+ return this._session;
+ }
+
+ public uploadFile(fileUri: string, options: IRequest): Task {
+ if (!fileUri) {
+ throw new Error('File must be provided.');
+ }
+
+ const url = NSURL.URLWithString(options.url);
+ const request = NSMutableURLRequest.requestWithURL(url);
+
+ const headers = options.headers;
+ if (headers) {
+ for (let header in headers) {
+ const value = headers[header];
+ if (value !== null && value !== void 0) {
+ request.setValueForHTTPHeaderField(value.toString(), header);
}
-
- let fileURL: NSURL;
- if (fileUri.substr(0, 7) === "file://") {
- // File URI in string format
- fileURL = NSURL.URLWithString(fileUri);
- } else if (fileUri.charAt(0) === "/") {
- // Absolute path with leading slash
- fileURL = NSURL.fileURLWithPath(fileUri);
- }
-
- const newTask = this._session.uploadTaskWithRequestFromFile(request, fileURL);
- newTask.taskDescription = options.description;
- newTask.resume();
- const retTask: Task = Task.getTask(this._session, newTask);
- return retTask;
- }
- public multipartUpload(params: any[], options: any): Task {
- const MPF = new MultiMultiPartForm();
- for (let i = 0; i < params.length; i++) {
- const curParam = params[i];
- if (typeof curParam.name === 'undefined') {
- throw new Error("You must have a `name` value");
- }
-
- if (curParam.filename) {
- const destFileName = curParam.destFilename || curParam.filename.substring(curParam.filename.lastIndexOf('/') + 1, curParam.filename.length);
- MPF.appendParam(curParam.name, null, curParam.filename, curParam.mimeType, destFileName);
- } else {
- MPF.appendParam(curParam.name, curParam.value);
- }
- }
- const header = MPF.getHeader();
- const uploadFile = MPF.generateFile();
-
- if (!options.headers) {
- options.headers = {};
- }
- options.headers['Content-Type'] = header['Content-Type'];
-
- const task = this.uploadFile(uploadFile, options);
-
- // Tag the file to be deleted and cleanup after upload
- (task)._fileToCleanup = uploadFile;
- return task;
- }
- static getSession(id: string): Session {
- let jsSession = Session._sessions[id];
- if (jsSession) {
- return jsSession;
- }
- jsSession = new Session(id);
- Session._sessions[id] = jsSession;
- return jsSession;
- }
+ }
+ }
+
+ if (options.method) {
+ request.HTTPMethod = options.method;
+ }
+
+ if (options.timeout) {
+ request.timeoutInterval = options.timeout;
+ }
+
+ let fileURL: NSURL;
+ if (fileUri.substr(0, 7) === 'file://') {
+ // File URI in string format
+ fileURL = NSURL.URLWithString(fileUri);
+ } else if (fileUri.charAt(0) === '/') {
+ // Absolute path with leading slash
+ fileURL = NSURL.fileURLWithPath(fileUri);
+ }
+
+ const newTask = this._session.uploadTaskWithRequestFromFile(request, fileURL);
+ newTask.taskDescription = options.description;
+ newTask.resume();
+ const retTask: Task = Task.getTask(this._session, newTask);
+ return retTask;
+ }
+ public multipartUpload(params: any[], options: any): Task {
+ const MPF = new MultiMultiPartForm();
+ for (let i = 0; i < params.length; i++) {
+ const curParam = params[i];
+ if (typeof curParam.name === 'undefined') {
+ throw new Error('You must have a `name` value');
+ }
+
+ if (curParam.filename) {
+ const destFileName = curParam.destFilename || curParam.filename.substring(curParam.filename.lastIndexOf('/') + 1, curParam.filename.length);
+ MPF.appendParam(curParam.name, null, curParam.filename, curParam.mimeType, destFileName);
+ } else {
+ MPF.appendParam(curParam.name, curParam.value);
+ }
+ }
+ const header = MPF.getHeader();
+ const uploadFile = MPF.generateFile();
+
+ if (!options.headers) {
+ options.headers = {};
+ }
+ options.headers['Content-Type'] = header['Content-Type'];
+
+ const task = this.uploadFile(uploadFile, options);
+
+ // Tag the file to be deleted and cleanup after upload
+ (task)._fileToCleanup = uploadFile;
+ return task;
+ }
+ static getSession(id: string): Session {
+ let jsSession = Session._sessions[id];
+ if (jsSession) {
+ return jsSession;
+ }
+ jsSession = new Session(id);
+ Session._sessions[id] = jsSession;
+ return jsSession;
+ }
}
class Task extends Observable {
- public static _tasks = new Map();
- private static is64BitArchitecture = interop.sizeof(interop.types.id) === 8;
- public static NSIntegerType = Task.is64BitArchitecture ? interop.types.int64 : interop.types.int32;
-
- public _fileToCleanup: string;
- private _task: NSURLSessionTask;
- private _session: NSURLSession;
-
- constructor(nsSession: NSURLSession, nsTask: NSURLSessionTask) {
- super();
- this._task = nsTask;
- this._session = nsSession;
- }
-
- get ios(): any {
- return this._task;
- }
-
- get description(): string {
- return this._task.taskDescription;
- }
-
- get upload(): number {
- return this._task.countOfBytesSent;
- }
-
- get totalUpload(): number {
- return this._task.countOfBytesExpectedToSend;
- }
-
- get status(): string {
- if (this._task.error) {
- return "error";
- }
- // NSURLSessionTaskState : NSInteger, so we should pass number format here
- switch (this._task.state) {
- case NSURLSessionTaskState.Running: return "uploading";
- case NSURLSessionTaskState.Completed: return "complete";
- case NSURLSessionTaskState.Canceling: return "error";
- case NSURLSessionTaskState.Suspended: return "pending";
- }
- }
-
- public static getTask(nsSession: NSURLSession, nsTask: NSURLSessionTask): Task {
- let task = Task._tasks.get(nsTask);
- if (task) {
- return task;
- }
-
- task = new Task(nsSession, nsTask);
- Task._tasks.set(nsTask, task);
-
- return task;
- }
-
- public cancel(): void {
- this._task.cancel();
- }
+ public static _tasks = new Map();
+ private static is64BitArchitecture = interop.sizeof(interop.types.id) === 8;
+ public static NSIntegerType = Task.is64BitArchitecture ? interop.types.int64 : interop.types.int32;
+
+ public _fileToCleanup: string;
+ private _task: NSURLSessionTask;
+ private _session: NSURLSession;
+
+ constructor(nsSession: NSURLSession, nsTask: NSURLSessionTask) {
+ super();
+ this._task = nsTask;
+ this._session = nsSession;
+ }
+
+ get ios(): any {
+ return this._task;
+ }
+
+ get description(): string {
+ return this._task.taskDescription;
+ }
+
+ get upload(): number {
+ return this._task.countOfBytesSent;
+ }
+
+ get totalUpload(): number {
+ return this._task.countOfBytesExpectedToSend;
+ }
+
+ get status(): string {
+ if (this._task.error) {
+ return 'error';
+ }
+ // NSURLSessionTaskState : NSInteger, so we should pass number format here
+ switch (this._task.state) {
+ case NSURLSessionTaskState.Running:
+ return 'uploading';
+ case NSURLSessionTaskState.Completed:
+ return 'complete';
+ case NSURLSessionTaskState.Canceling:
+ return 'error';
+ case NSURLSessionTaskState.Suspended:
+ return 'pending';
+ }
+ }
+
+ public static getTask(nsSession: NSURLSession, nsTask: NSURLSessionTask): Task {
+ let task = Task._tasks.get(nsTask);
+ if (task) {
+ return task;
+ }
+
+ task = new Task(nsSession, nsTask);
+ Task._tasks.set(nsTask, task);
+
+ return task;
+ }
+
+ public cancel(): void {
+ this._task.cancel();
+ }
}
export function session(id: string): Session {
- return Session.getSession(id);
+ return Session.getSession(id);
}
class MultiMultiPartForm {
- private boundary: string;
- private header: any;
- private fileCount: number;
- private fields: Array;
-
- constructor() {
- this.clear();
- }
-
- public clear(): void {
- this.boundary = "--------------formboundary" + Math.floor(Math.random() * 100000000000);
- this.header = { "Content-Type": 'multipart/form-data; boundary=' + this.boundary };
- this.fileCount = 0;
- this.fields = [];
- }
-
- public appendParam(name: string, value: string, filename?: string, mimeType?: string, destFileName?: string): void {
- // If all we are doing is passing a field, we just add it to the fields list
- if (filename == null) {
- this.fields.push({ name: name, value: value });
- return;
- }
- // Load file
- mimeType = mimeType || "application/data";
-
- if (filename.startsWith("~/")) {
- filename = filename.replace("~/", knownFolders.currentApp().path + "/");
- }
-
- const finalName = destFileName || filename.substr(filename.lastIndexOf('/') + 1, filename.length);
- this.fields.push({ name: name, filename: filename, destFilename: finalName, mimeType: mimeType });
- }
-
- public generateFile(): string {
- const CRLF = "\r\n";
-
- const fileName = knownFolders.documents().path + "/temp-MPF-" + Math.floor(Math.random() * 100000000000) + ".tmp";
-
- const combinedData = NSMutableData.alloc().init();
-
- let results: string = "";
- let tempString: NSString;
- let newData: any;
- for (let i = 0; i < this.fields.length; i++) {
- results += "--" + this.boundary + CRLF;
- results += 'Content-Disposition: form-data; name="' + this.fields[i].name + '"';
- if (!this.fields[i].filename) {
- results += CRLF + CRLF + this.fields[i].value + CRLF;
- } else {
- results += '; filename="' + this.fields[i].destFilename + '"';
- if (this.fields[i].mimeType) {
- results += CRLF + "Content-Type: " + this.fields[i].mimeType;
- }
- results += CRLF + CRLF;
- }
-
- tempString = NSString.stringWithString(results);
- results = "";
- newData = tempString.dataUsingEncoding(NSUTF8StringEncoding);
- combinedData.appendData(newData);
-
-
- if (this.fields[i].filename) {
- const fileData = NSData.alloc().initWithContentsOfFile(this.fields[i].filename);
- combinedData.appendData(fileData);
- results = CRLF;
- }
-
- }
- // Add final part of it...
- results += "--" + this.boundary + "--" + CRLF;
- tempString = NSString.stringWithString(results);
- newData = tempString.dataUsingEncoding(NSUTF8StringEncoding);
- combinedData.appendData(newData);
-
- NSFileManager.defaultManager.createFileAtPathContentsAttributes(fileName, combinedData, null);
-
- return fileName;
- }
-
- public getHeader(): string {
- return this.header;
- }
+ private boundary: string;
+ private header: any;
+ private fileCount: number;
+ private fields: Array;
+
+ constructor() {
+ this.clear();
+ }
+
+ public clear(): void {
+ this.boundary = '--------------formboundary' + Math.floor(Math.random() * 100000000000);
+ this.header = { 'Content-Type': 'multipart/form-data; boundary=' + this.boundary };
+ this.fileCount = 0;
+ this.fields = [];
+ }
+
+ public appendParam(name: string, value: string, filename?: string, mimeType?: string, destFileName?: string): void {
+ // If all we are doing is passing a field, we just add it to the fields list
+ if (filename == null) {
+ this.fields.push({ name: name, value: value });
+ return;
+ }
+ // Load file
+ mimeType = mimeType || 'application/data';
+
+ if (filename.startsWith('~/')) {
+ filename = filename.replace('~/', knownFolders.currentApp().path + '/');
+ }
+
+ const finalName = destFileName || filename.substr(filename.lastIndexOf('/') + 1, filename.length);
+ this.fields.push({ name: name, filename: filename, destFilename: finalName, mimeType: mimeType });
+ }
+
+ public generateFile(): string {
+ const CRLF = '\r\n';
+
+ const fileName = knownFolders.documents().path + '/temp-MPF-' + Math.floor(Math.random() * 100000000000) + '.tmp';
+
+ const combinedData = NSMutableData.alloc().init();
+
+ let results: string = '';
+ let tempString: NSString;
+ let newData: any;
+ for (let i = 0; i < this.fields.length; i++) {
+ results += '--' + this.boundary + CRLF;
+ results += 'Content-Disposition: form-data; name="' + this.fields[i].name + '"';
+ if (!this.fields[i].filename) {
+ results += CRLF + CRLF + this.fields[i].value + CRLF;
+ } else {
+ results += '; filename="' + this.fields[i].destFilename + '"';
+ if (this.fields[i].mimeType) {
+ results += CRLF + 'Content-Type: ' + this.fields[i].mimeType;
+ }
+ results += CRLF + CRLF;
+ }
+
+ tempString = NSString.stringWithString(results);
+ results = '';
+ newData = tempString.dataUsingEncoding(NSUTF8StringEncoding);
+ combinedData.appendData(newData);
+
+ if (this.fields[i].filename) {
+ const fileData = NSData.alloc().initWithContentsOfFile(this.fields[i].filename);
+ combinedData.appendData(fileData);
+ results = CRLF;
+ }
+ }
+ // Add final part of it...
+ results += '--' + this.boundary + '--' + CRLF;
+ tempString = NSString.stringWithString(results);
+ newData = tempString.dataUsingEncoding(NSUTF8StringEncoding);
+ combinedData.appendData(newData);
+
+ NSFileManager.defaultManager.createFileAtPathContentsAttributes(fileName, combinedData, null);
+
+ return fileName;
+ }
+
+ public getHeader(): string {
+ return this.header;
+ }
}
diff --git a/packages/datetimepicker/index.android.ts b/packages/datetimepicker/index.android.ts
index b20d493a..93491321 100644
--- a/packages/datetimepicker/index.android.ts
+++ b/packages/datetimepicker/index.android.ts
@@ -276,8 +276,8 @@ export class DateTimePicker extends DateTimePickerBase {
private static _applyNumberPickerColor(numberPicker: android.widget.NumberPicker, color: Color) {
const sdkVersionInt = parseInt(Device.sdkVersion, 10);
if (sdkVersionInt >= 29) {
- numberPicker.setTextColor(color.android);
- return;
+ numberPicker.setTextColor(color.android);
+ return;
}
const wheelPaint = DateTimePicker._findFieldByName(numberPicker, 'mSelectorWheelPaint');
const selectionDividerDrawable = DateTimePicker._findFieldByName(numberPicker, 'mSelectionDivider');
diff --git a/packages/facebook/index.android.ts b/packages/facebook/index.android.ts
index cf4af830..5d3e01ca 100644
--- a/packages/facebook/index.android.ts
+++ b/packages/facebook/index.android.ts
@@ -301,7 +301,7 @@ export class LoginManager implements ILoginManager {
onError(param0: com.facebook.FacebookException) {
reject(FacebookError.fromNative(param0 as any));
},
- }),
+ })
);
this.#native.logIn(context || Application.android.foregroundActivity || Application.android.startActivity, java.util.Arrays.asList(permissions));
});
diff --git a/packages/google-maps-utils/.eslintrc.json b/packages/google-maps-utils/.eslintrc.json
new file mode 100644
index 00000000..53c06c8d
--- /dev/null
+++ b/packages/google-maps-utils/.eslintrc.json
@@ -0,0 +1,18 @@
+{
+ "extends": ["../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*", "node_modules/**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.ts", "*.tsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.js", "*.jsx"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/packages/google-maps-utils/README.md b/packages/google-maps-utils/README.md
new file mode 100644
index 00000000..0289874d
--- /dev/null
+++ b/packages/google-maps-utils/README.md
@@ -0,0 +1,98 @@
+# @nativescript/google-maps-utils
+
+```javascript
+ns plugin add @nativescript/google-maps-utils
+```
+*Requires google maps plugin [@nativescript/google-maps](packages/google-maps/README.md)*
+
+## Installation
+Install the mixins to the GoogleMaps object
+```javascript
+import { installMixins } from '@nativescript/google-maps-utils';
+installMixins();
+```
+
+## Usage
+You can access the google maps utilities from the GoogleMaps object after the mixins have been installed.
+```javascript
+onMapReady(args: MapReadyEvent) {
+ const map = args.map;
+}
+```
+
+---
+
+## HeatMaps
+```javascript
+import { HeatmapTileProvider, HeatmapOptions } from '@nativescript/google-maps-utils';
+import { GoogleMap, Coordinate } from '@nativescript/google-maps';
+
+addHeatmapOverlay(map: GoogleMap, heatmapOptions: HeatmapOptions) {
+ // Create a new heat map tile provider
+ const heatmapProvider = new HeatmapTileProvider(heatmapOptions);
+ // Pass tile provider to Google Maps
+ const heatmapOverlay = map.addTileOverlay({
+ tileProvider: heatmapProvider,
+ });
+}
+```
+
+### HeatmapOptions
+
+| Property | Type
+|:---------|:-----
+| `coordinates` | `Coordinate[]`;
+| `opacity` | `number`;
+| `radius` | `number`;
+| `maxIntensity` | `number`;
+| `gradient` | ` IGradient[]`;
+
+---
+
+## Clustering
+```javascript
+import { ClusterManager } from '@nativescript/google-maps-utils';
+import { GoogleMap, MarkerOptions } from '@nativescript/google-maps';
+
+addClusteredMarkers(map: GoogleMap, markers: MarkerOptions[]) {
+ const clusterManager: ClusterManager = map.clusterManager(markers);
+}
+```
+
+---
+
+## Experimental Features
+Features that are not yet fully implemented or likely to change.
+### GeoJson Layers
+
+Currently only supports GeoJson Objects.
+
+```javascript
+import { GeoJsonLayer, IGeometryStyle } from '@nativescript/google-maps-utils';
+
+onMapReady(args: MapReadyEvent) {
+ const style: Partial = {
+ fillColor: new Color('blue'),
+ strokeColor: new Color('red'),
+ width: 4,
+ }
+
+ map.addGeoJson({
+ geoJson: geoJson,
+ style: style,
+ });
+}
+```
+
+```javascript
+import { GeoJsonLayer } from '@nativescript/google-maps-utils';
+
+removeGeoJsonLayer(map: GoogleMap, layer: GeoJsonLayer) {
+ map.removeGeoJson(layer);
+}
+```
+
+
+## License
+
+Apache License Version 2.0
diff --git a/packages/google-maps-utils/experimental/datalayer/index.android.ts b/packages/google-maps-utils/experimental/datalayer/index.android.ts
new file mode 100644
index 00000000..1e99bafa
--- /dev/null
+++ b/packages/google-maps-utils/experimental/datalayer/index.android.ts
@@ -0,0 +1,339 @@
+import { Color } from '@nativescript/core';
+import { GoogleMap } from '@nativescript/google-maps';
+import { intoNativeColor } from '../../../google-maps-utils/utils';
+import { IGeometryStyle, IGeoJsonLayer, IFeature, IGeometry } from '.';
+
+export abstract class DataLayer {
+ abstract readonly native: T;
+
+ // setMap(map: com.google.android.gms.maps.GoogleMap) {
+ // this.native.setMap(map);
+ // }
+
+ // getDefaultPolygonStyle() {
+ // return this.native.getDefaultPolygonStyle();
+ // }
+
+ addLayerToMap() {
+ this.native.addLayerToMap();
+ }
+
+ // isLayerOnMap(): boolean {
+ // return this.native.isLayerOnMap();
+ // }
+
+ removeLayerFromMap() {
+ this.native.removeLayerFromMap();
+ }
+
+ // hasFeatures(): boolean {
+ // return this.native.hasFeatures();
+ // }
+
+ // getFeature(feature: any) {
+ // return this.native.getFeature(feature);
+ // }
+
+ // getFeatures(): any {
+ // return this.native.getFeatures();
+ // }
+
+ // addFeature(feature: com.google.maps.android.data.geojson.GeoJsonFeature) {
+ // return this.native.addFeature(feature);
+ // }
+
+ // removeFeature(feature: com.google.maps.android.data.geojson.GeoJsonFeature) {
+ // this.native.removeFeature(feature);
+ // }
+
+ get android() {
+ return this.native;
+ }
+
+ // public hasContainers(): boolean;
+ // public addKMLToMap(): void;
+ // public getDefaultPointStyle(): com.google.maps.android.data.geojson.GeoJsonPointStyle;
+ // public setOnFeatureClickListener(param0: com.google.maps.android.data.Layer.OnFeatureClickListener): void;
+ // public removeFeature(param0: com.google.maps.android.data.Feature): void;
+ // public getMap(): com.google.android.gms.maps.GoogleMap;
+ // public addGeoJsonToMap(): void;
+ // public getDefaultLineStringStyle(): com.google.maps.android.data.geojson.GeoJsonLineStringStyle;
+ // public storeRenderer(param0: com.google.maps.android.data.Renderer): void;
+ // public getContainers(): java.lang.Iterable;
+ // public getContainerFeature(param0: any): com.google.maps.android.data.Feature;
+ // public getGroundOverlays(): java.lang.Iterable;
+}
+
+export class KmlGeometryStyle implements IGeometryStyle {
+ constructor(public getPolygonOptions: com.google.android.gms.maps.model.PolygonOptions, public getPolylineOptions: com.google.android.gms.maps.model.PolylineOptions, public kerOptions: com.google.android.gms.maps.model.MarkerOptions) {}
+
+ get strokeColor(): Color {
+ return intoNativeColor(this.getPolygonOptions.getStrokeColor().toString());
+ }
+ fillColor: Color;
+ width: number;
+ scale: number;
+ heading: number;
+ anchor: [number, number];
+ iconUrl: string;
+ title: string;
+}
+export class GeoJsonGeometryStyle implements Partial {
+ constructor(private polygonStyle: com.google.maps.android.data.geojson.GeoJsonPolygonStyle, private lineStyle: com.google.maps.android.data.geojson.GeoJsonLineStringStyle, private pointStyle: com.google.maps.android.data.geojson.GeoJsonPointStyle) {}
+
+ get strokeColor() {
+ return new Color(this.polygonStyle.getStrokeColor());
+ }
+ set strokeColor(color: Color) {
+ this.polygonStyle.setStrokeColor(color.android);
+ this.lineStyle.setColor(color.android);
+ }
+
+ get fillColor() {
+ return new Color(this.polygonStyle.getFillColor());
+ }
+ set fillColor(color: Color) {
+ this.polygonStyle.setFillColor(color.android);
+ }
+
+ get width(): number {
+ return this.lineStyle.getWidth();
+ }
+ set width(width: number) {
+ this.lineStyle.setWidth(width);
+ this.polygonStyle.setStrokeWidth(width);
+ }
+
+ get title() {
+ return this.pointStyle.getTitle();
+ }
+ set title(title: string) {
+ this.pointStyle.setTitle(title);
+ }
+
+ get heading(): number {
+ return this.pointStyle.getRotation();
+ }
+ set heading(rotation: number) {
+ // Marker roation or rotation???
+ this.pointStyle.setRotation(rotation);
+ // this.pointStyle.setMarkerRotation(rotation);
+ }
+}
+
+export class GeoJsonLayer extends DataLayer implements IGeoJsonLayer {
+ #native: com.google.maps.android.data.geojson.GeoJsonLayer;
+ style: GeoJsonGeometryStyle;
+
+ constructor(map: GoogleMap, geoJson: any, geometryStyle?: IGeometryStyle) {
+ super();
+ if (map && geoJson) {
+ try {
+ const geoJsonData = new org.json.JSONObject(JSON.stringify(geoJson));
+ this.#native = new com.google.maps.android.data.geojson.GeoJsonLayer(map.native, geoJsonData);
+ this.style = new GeoJsonGeometryStyle(this.#native.getDefaultPolygonStyle(), this.#native.getDefaultLineStringStyle(), this.#native.getDefaultPointStyle());
+
+ if (geometryStyle) {
+ for (const key of Object.keys(geometryStyle)) {
+ if (geometryStyle?.[key]) {
+ this.style[key] = geometryStyle?.[key];
+ }
+ }
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ }
+ }
+
+ static fromNative(nativeGeoJsonLayer: com.google.maps.android.data.geojson.GeoJsonLayer) {
+ if (nativeGeoJsonLayer instanceof com.google.maps.android.data.geojson.GeoJsonLayer) {
+ const geoJsonLayer = new GeoJsonLayer(null, null);
+ geoJsonLayer.#native = nativeGeoJsonLayer;
+ return geoJsonLayer;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get features() {
+ const features: GeoJsonFeature[] = [];
+ const nativeFeatures: java.lang.Iterable = this.native.getFeatures();
+
+ const iter = nativeFeatures.iterator();
+ while (iter.hasNext()) {
+ const feature = iter.next();
+ features.push(GeoJsonFeature.fromNative(feature));
+ }
+
+ return features;
+ }
+
+ // get bounds(): CoordinateBounds {
+ // const bounds = this.#native.getBoundingBox();
+ // if (bounds) {
+ // return {
+ // southwest: {
+ // lat: bounds?.southwest?.latitude,
+ // lng: bounds?.southwest?.longitude,
+ // },
+ // northeast: {
+ // lat: bounds?.northeast?.latitude,
+ // lng: bounds?.northeast?.longitude,
+ // },
+ // };
+ // }
+ // }
+
+ // toString() {
+ // return this.native.toString();
+ // }
+}
+
+export class KmlLayer extends DataLayer {
+ #native: com.google.maps.android.data.kml.KmlLayer;
+
+ constructor(mapView: com.google.android.gms.maps.GoogleMap, kml: org.json.JSONObject) {
+ super();
+ if (mapView && kml) {
+ this.#native = new com.google.maps.android.data.kml.KmlLayer();
+ this.#native.addLayerToMap();
+ this.#native.addKMLToMap();
+ }
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ hasPlacemarks(): boolean {
+ return this.native.hasPlacemarks();
+ }
+
+ getPlacemarks(): java.lang.Iterable {
+ return this.native.getPlacemarks();
+ }
+
+ getGroundOverlays(): java.lang.Iterable {
+ return this.native.getGroundOverlays();
+ }
+}
+abstract class BaseFeature implements IFeature {
+ abstract style: any;
+ abstract readonly native: T;
+
+ get android() {
+ return this.native;
+ }
+
+ get geometry() {
+ return Geometry.fromNative(this.native.getGeometry());
+ }
+
+ get id() {
+ return this.native.getId();
+ }
+
+ get properties() {
+ const props = {};
+
+ const iter = this.native.getPropertyKeys().iterator();
+ while (iter.hasNext()) {
+ const key = iter.next();
+ props[key] = this.native.getProperty(key);
+ }
+
+ return props;
+ }
+ set properties(value: any) {
+ Object.entries(value).forEach(([key, value]: [string, string]) => {
+ this.native.setProperty(key, value);
+ });
+ }
+}
+
+export class GeoJsonFeature extends BaseFeature {
+ #native: com.google.maps.android.data.geojson.GeoJsonFeature;
+ #style: GeoJsonGeometryStyle;
+
+ constructor() {
+ super();
+ }
+
+ static fromNative(nativeFeature: com.google.maps.android.data.geojson.GeoJsonFeature) {
+ if (nativeFeature instanceof com.google.maps.android.data.geojson.GeoJsonFeature) {
+ const feature = new GeoJsonFeature();
+ feature.#native = nativeFeature;
+ return feature;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get style() {
+ this.#style = new GeoJsonGeometryStyle(this.native.getPolygonStyle(), this.native.getLineStringStyle(), this.native.getPointStyle());
+ return this.#style;
+ }
+}
+
+export class KMLPlacemarkFeature extends BaseFeature {
+ #native: com.google.maps.android.data.kml.KmlPlacemark;
+ #style: GeoJsonGeometryStyle;
+
+ constructor() {
+ super();
+ }
+
+ static fromNative(nativeFeature: com.google.maps.android.data.kml.KmlPlacemark) {
+ if (nativeFeature instanceof com.google.maps.android.data.kml.KmlPlacemark) {
+ const feature = new KMLPlacemarkFeature();
+ feature.#native = nativeFeature;
+ return feature;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get style() {
+ // this.#style = new KmlGeometryStyle(this.native.getPolygonOptions(), this.native.getPolylineOptions(), this.native.getMarkerOptions());
+ return this.#style;
+ }
+}
+
+export class Geometry implements IGeometry {
+ #native: com.google.maps.android.data.Geometry;
+
+ static fromNative(nativeGeometry: com.google.maps.android.data.Geometry) {
+ if (nativeGeometry instanceof com.google.maps.android.data.Geometry) {
+ const geometry = new Geometry();
+ geometry.#native = nativeGeometry;
+ return geometry;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get android() {
+ return this.native;
+ }
+
+ get type() {
+ return this.native.getGeometryType();
+ }
+
+ get geometries() {
+ return this.native.getGeometryObject();
+ }
+}
diff --git a/packages/google-maps-utils/experimental/datalayer/index.d.ts b/packages/google-maps-utils/experimental/datalayer/index.d.ts
new file mode 100644
index 00000000..d3baafda
--- /dev/null
+++ b/packages/google-maps-utils/experimental/datalayer/index.d.ts
@@ -0,0 +1,71 @@
+export interface IGeoJsonLayer {
+ style: GeometryStyle;
+ addLayerToMap: () => void;
+ removeLayerFromMap: () => void;
+}
+
+export class GeoJsonLayer implements IGeoJsonLayer {
+ ios: any;
+ android: any;
+ native: any;
+ style: GeometryStyle;
+ features: GeoJsonFeature[];
+ constructor(map: GoogleMap, geojson: any, styles?: Partial);
+ addLayerToMap: () => void;
+ removeLayerFromMap: () => void;
+}
+
+export interface IGeometryStyle {
+ /**
+ * The color for the stroke of a LineString or Polygon.
+ */
+ strokeColor: Color;
+
+ /**
+ * The color for the fill of a Polygon.
+ */
+ fillColor: Color;
+
+ /**
+ * The width of a LineString
+ */
+ width: number;
+
+ /**
+ * The scale that a Point's icon should be rendered at.
+ */
+ scale: number;
+
+ /**
+ * The direction, in degrees, that a Point's icon should be rendered at.
+ */
+ heading: number;
+
+ /**
+ * The position within an icon that is anchored to the Point.
+ */
+ anchor: [number, number];
+
+ /**
+ * Icon Url
+ */
+ iconUrl: string | null;
+
+ /**
+ * The title of the point
+ */
+ title: string | null;
+ // hasFill: boolean;
+ // hasStroke: boolean;
+}
+
+export interface IGeometry {
+ type: string;
+ geometries: any;
+}
+
+export interface IFeature {
+ geometry: any;
+ properties: any;
+ id: any;
+}
diff --git a/packages/google-maps-utils/experimental/datalayer/index.ios.ts b/packages/google-maps-utils/experimental/datalayer/index.ios.ts
new file mode 100644
index 00000000..cd8dd7c5
--- /dev/null
+++ b/packages/google-maps-utils/experimental/datalayer/index.ios.ts
@@ -0,0 +1,167 @@
+import { Color, encoding } from '@nativescript/core';
+import { GoogleMap } from '@nativescript/google-maps';
+import { IGeometryStyle, IGeoJsonLayer, IFeature, IGeometry } from '.';
+
+let UNIQUE_STYLE_ID = 0;
+
+export class GeometryStyle implements IGeometryStyle {
+ #native: GMUStyle;
+
+ constructor(public geometryStyles: Partial) {
+ Object.assign(this, geometryStyles);
+
+ this.#native = new GMUStyle({
+ styleID: `google-maps-utils-style-${UNIQUE_STYLE_ID++}`,
+ strokeColor: this.strokeColor?.ios ?? null,
+ fillColor: this.fillColor?.ios ?? null,
+ width: this.width ?? 1,
+ scale: this.scale ?? 0,
+ heading: this.heading ?? 0,
+ anchor: CGPointMake(this.anchor?.[0] ?? 0, this.anchor?.[1] ?? 0),
+ iconUrl: this.iconUrl ?? null,
+ title: this.title ?? null,
+ hasFill: !!this.fillColor,
+ hasStroke: !!this.strokeColor,
+ } as any);
+ }
+
+ strokeColor: Color;
+ fillColor: Color;
+ width: number;
+ scale: number;
+ heading: number;
+ anchor: [number, number];
+ iconUrl: string;
+ title: string;
+
+ get native() {
+ return this.#native;
+ }
+}
+
+export class GeoJsonLayer implements IGeoJsonLayer {
+ #native: GMUGeometryRenderer;
+ #parser: GMUGeoJSONParser;
+ style: GeometryStyle;
+
+ constructor(private map: GoogleMap, private geometries: any, private styles?: Partial) {
+ this.style = new GeometryStyle(styles);
+
+ const jsonString = new NSString({ UTF8String: JSON.stringify(geometries) });
+ this.#parser = new GMUGeoJSONParser({ data: jsonString.dataUsingEncoding(encoding.UTF_8) });
+ this.#parser.parse();
+
+ const features = this.#parser.features;
+ for (const feature of features) {
+ feature.style = this.style.native;
+ }
+
+ this.#native = new GMUGeometryRenderer({ map: this.map.native, geometries: features });
+ }
+
+ static fromNative(nativeGeoJsonLayer: GMUGeometryRenderer) {
+ if (nativeGeoJsonLayer instanceof GMUGeometryRenderer) {
+ const geoJsonLayer = new GeoJsonLayer(null, null, null);
+ geoJsonLayer.#native = nativeGeoJsonLayer;
+ return geoJsonLayer;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get ios() {
+ return this.native;
+ }
+
+ get features() {
+ // const features = [];
+ // for (const feature of this.#parser.features) {
+ // const f = feature as GMUGeometryContainer;
+
+ // GeoJsonFeature.fromNative(f);
+ // f.geometry;
+ // f.style;
+ // }
+ return null;
+ }
+
+ addLayerToMap() {
+ this.native.render();
+ }
+
+ removeLayerFromMap() {
+ this.native.clear();
+ }
+}
+
+export class GeoJsonFeature implements IFeature {
+ #native: GMUGeometryCollection;
+
+ static fromNative(nativeGeometryContainer: GMUGeometryCollection) {
+ if (nativeGeometryContainer instanceof GMUGeometryCollection) {
+ const geoJsonFeature = new GeoJsonFeature();
+ geoJsonFeature.#native = nativeGeometryContainer;
+ return geoJsonFeature;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get ios() {
+ return this.#native;
+ }
+
+ get geometry() {
+ const geometries = [];
+
+ for (const geometry of this.native.geometries) {
+ geometries.push(Geometry.fromNative(geometry));
+ }
+
+ return geometries;
+ }
+
+ get properties() {
+ return;
+ }
+
+ get id() {
+ return this.native.description;
+ }
+}
+
+export class Geometry implements IGeometry {
+ #native: GMUGeometry;
+
+ static fromNative(nativeGeometry: GMUGeometry) {
+ if (nativeGeometry) {
+ console.log(nativeGeometry.class().name);
+ const geometry = new Geometry();
+ geometry.#native = nativeGeometry;
+ return geometry;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get ios() {
+ return this.#native;
+ }
+
+ get type() {
+ return this.#native.type;
+ }
+
+ get geometries() {
+ return this.native;
+ }
+}
diff --git a/packages/google-maps-utils/experimental/iconfactory/index.android.ts b/packages/google-maps-utils/experimental/iconfactory/index.android.ts
new file mode 100644
index 00000000..9d8c6f41
--- /dev/null
+++ b/packages/google-maps-utils/experimental/iconfactory/index.android.ts
@@ -0,0 +1,56 @@
+import { Color, Utils } from '@nativescript/core';
+import { IIconFactory } from '.';
+
+export enum ICON_STYLE {
+ STYLE_DEFAULT = 1,
+ STYLE_WHITE = 2,
+ STYLE_RED = 3,
+ STYLE_BLUE = 4,
+ STYLE_GREEN = 5,
+ STYLE_ORANGE = 7,
+ STYLE_PURPLE = 6,
+}
+
+export class IconFactory implements IIconFactory {
+ #native: com.google.maps.android.ui.IconGenerator;
+
+ constructor() {
+ this.#native = new com.google.maps.android.ui.IconGenerator(Utils.ad.getApplicationContext());
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get android() {
+ return this.native;
+ }
+
+ set backgroundAsset(value: globalAndroid.graphics.drawable.Drawable) {
+ this.native.setBackground(value);
+ }
+
+ set color(color: Color) {
+ this.#native.setColor(color.android);
+ }
+
+ set rotation(rotation: number) {
+ this.#native.setRotation(rotation);
+ }
+
+ set contentRotation(rotation: number) {
+ this.#native.setContentRotation(rotation);
+ }
+
+ setStyle(style: ICON_STYLE) {
+ this.#native.setStyle(style);
+ }
+
+ setTextAppearance(appearance: number) {
+ this.#native.setTextAppearance(appearance);
+ }
+
+ makeIcon(text: string): globalAndroid.graphics.Bitmap {
+ return this.#native.makeIcon(text);
+ }
+}
diff --git a/packages/google-maps-utils/experimental/iconfactory/index.d.ts b/packages/google-maps-utils/experimental/iconfactory/index.d.ts
new file mode 100644
index 00000000..2a38d425
--- /dev/null
+++ b/packages/google-maps-utils/experimental/iconfactory/index.d.ts
@@ -0,0 +1,25 @@
+import { Color } from '@nativescript/core';
+
+export interface IIconFactory {
+ setStyle(style: number);
+ setTextAppearance(style: number);
+ makeIcon(text: string);
+ color: Color;
+ backgroundAsset: any;
+ rotation: number;
+ contentRotation: number;
+ native: any;
+}
+
+export class IconFactory implements IIconFactory {
+ setStyle(style: number);
+ setTextAppearance(style: number);
+ makeIcon(text: string);
+ color: Color;
+ backgroundAsset: any;
+ rotation: number;
+ contentRotation: number;
+ android?: any;
+ ios?: any;
+ native?: any;
+}
diff --git a/packages/google-maps-utils/experimental/iconfactory/index.ios.ts b/packages/google-maps-utils/experimental/iconfactory/index.ios.ts
new file mode 100644
index 00000000..e0d61d82
--- /dev/null
+++ b/packages/google-maps-utils/experimental/iconfactory/index.ios.ts
@@ -0,0 +1,33 @@
+import { Color } from '@nativescript/core';
+import { IIconFactory } from '.';
+
+export enum ICON_STYLE {
+ STYLE_DEFAULT = 1,
+ STYLE_WHITE = 2,
+ STYLE_RED = 3,
+ STYLE_BLUE = 4,
+ STYLE_GREEN = 5,
+ STYLE_ORANGE = 7,
+ STYLE_PURPLE = 6,
+}
+
+export class IconFactory implements IIconFactory {
+ // Not provided in iOS google-maps-util library. Need to roll our own impl.
+ setStyle(style: number) {
+ console.error('Method not implemented.');
+ }
+ makeIcon(text: string) {
+ console.error('Method not implemented.');
+ return GMSMarker.markerImageWithColor(new Color('red').ios);
+ }
+ setTextAppearance(style: number) {
+ console.error('Method not implemented.');
+ }
+
+ color: Color;
+ backgroundAsset: any;
+ rotation: number;
+ contentRotation: number;
+ ios: any;
+ native: any;
+}
diff --git a/packages/google-maps-utils/index.android.ts b/packages/google-maps-utils/index.android.ts
new file mode 100644
index 00000000..51ef11ef
--- /dev/null
+++ b/packages/google-maps-utils/index.android.ts
@@ -0,0 +1,510 @@
+import { Color, ImageSource, Utils } from '@nativescript/core';
+import { GeoJSON } from 'geojson';
+import { Coordinate, GoogleMap, ITileProvider, MarkerOptions, hueFromColor } from '@nativescript/google-maps';
+import { HeatmapOptions, IClusterManager, IFeature, IGeoJsonLayer, IGeometry, IGeometryStyle, IGradient, IHeatmapTileProvider } from '.';
+import { applyMixins } from './utils/common';
+import { intoNativeClusterManager, intoNativeColor, intoNativeHeatmapGradient, intoNativeHeatmapProvider } from './utils';
+
+// export * from './experimental/datalayer';
+// export * from './experimental/iconfactory';
+export * from './utils';
+
+let mixinInstalled = false;
+export function overrideGoogleMap() {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ const GMap = require('@nativescript/google-maps').GoogleMap;
+ applyMixins(GMap, [GoogleMapUtils], { after: true });
+}
+
+export function installMixins() {
+ if (!mixinInstalled) {
+ mixinInstalled = true;
+ overrideGoogleMap();
+ }
+}
+
+export class GoogleMapUtils {
+ clusterManager(markers: MarkerOptions[]) {
+ const GMap = this as unknown as GoogleMap;
+ const clusterManager = ClusterManager.fromNative(intoNativeClusterManager(GMap));
+ const renderer = new ClusterRenderer(GMap, clusterManager);
+ clusterManager.setRenderer(renderer);
+
+ const clusters = markers.map((marker) => new ClusterItem(marker));
+ clusterManager.addItems(clusters);
+
+ clusterManager.cluster();
+
+ return clusterManager;
+ }
+
+ addGeoJson(geoJson: GeoJSON, styleOptions: IGeometryStyle) {
+ if ((this as unknown as GoogleMap) && geoJson) {
+ const geoJsonData = new org.json.JSONObject(JSON.stringify(geoJson));
+ const native = new com.google.maps.android.data.geojson.GeoJsonLayer((this as unknown as GoogleMap).native, geoJsonData);
+ const style = new GeoJsonGeometryStyle(native.getDefaultPolygonStyle(), native.getDefaultLineStringStyle(), native.getDefaultPointStyle());
+
+ if (styleOptions) {
+ for (const key of Object.keys(styleOptions)) {
+ if (styleOptions?.[key]) {
+ style[key] = styleOptions?.[key];
+ }
+ }
+ }
+
+ native.addLayerToMap();
+
+ return GeoJsonLayer.fromNative(native);
+ }
+ return null;
+ }
+
+ removeGeoJson(geoJson: GeoJsonLayer) {
+ if (geoJson) {
+ geoJson.removeLayerFromMap();
+ }
+ }
+}
+
+export class HeatmapTileProvider implements ITileProvider, IHeatmapTileProvider {
+ #native: com.google.maps.android.heatmaps.HeatmapTileProvider;
+
+ constructor(options?: HeatmapOptions) {
+ if (options) {
+ this.#native = intoNativeHeatmapProvider(options);
+ }
+ }
+
+ static fromNative(nativeHeatmap: com.google.maps.android.heatmaps.HeatmapTileProvider) {
+ if (nativeHeatmap instanceof com.google.maps.android.heatmaps.HeatmapTileProvider) {
+ const heatmap = new HeatmapTileProvider();
+ heatmap.#native = nativeHeatmap;
+ return heatmap;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ set opacity(opacity: number) {
+ this.native.setOpacity(opacity);
+ }
+
+ setGradient(gradients: IGradient[]): void {
+ this.native.setGradient(intoNativeHeatmapGradient(gradients));
+ }
+
+ set radius(radius: number) {
+ this.native.setRadius(radius);
+ }
+
+ set maxIntensity(maxIntensity: number) {
+ this.native.setMaxIntensity(maxIntensity);
+ }
+
+ setData(coordinates: Coordinate[]): void {
+ const data = new java.util.ArrayList();
+
+ coordinates.forEach((coordinate) => {
+ data.add(new com.google.android.gms.maps.model.LatLng(coordinate.lat, coordinate.lng));
+ });
+
+ this.native.setData(data);
+ }
+
+ getTile(x: number, y: number, z: number): com.google.android.gms.maps.model.Tile {
+ return this.native.getTile(x, y, z);
+ }
+}
+
+export class ClusterItem extends com.google.maps.android.clustering.ClusterItem {
+ constructor(public options: MarkerOptions) {
+ super({
+ getPosition: (): com.google.android.gms.maps.model.LatLng => {
+ return new com.google.android.gms.maps.model.LatLng(options?.position?.lat ?? 0, options?.position?.lng ?? 0);
+ },
+ getSnippet: (): string => {
+ return this.options?.snippet ?? '';
+ },
+ getTitle: (): string => {
+ return this.options?.title ?? '';
+ },
+ getZIndex: (): any => {
+ return java.lang.Float.valueOf(this.options?.zIndex ?? 0);
+ },
+ });
+ }
+}
+
+export class ClusterRenderer extends com.google.maps.android.clustering.view.DefaultClusterRenderer {
+ constructor(map: GoogleMap, clusterManager: ClusterManager) {
+ super(Utils.ad.getApplicationContext(), map.native, clusterManager.native);
+ }
+
+ override onBeforeClusterItemRendered(item: ClusterItem, opts: com.google.android.gms.maps.model.MarkerOptions): void {
+ super.onBeforeClusterItemRendered(item, opts);
+
+ if (typeof item.options?.draggable === 'boolean') {
+ opts.draggable(item.options.draggable);
+ }
+
+ if (typeof item.options?.anchorU === 'number' || typeof item.options?.anchorV === 'number') {
+ const anchorU = item.options?.anchorU ?? opts.getAnchorU();
+ const anchorV = item.options?.anchorV ?? opts?.getAnchorV();
+ opts.anchor(anchorU, anchorV);
+ }
+
+ if (item.options?.position) {
+ opts.position(new com.google.android.gms.maps.model.LatLng(item.options.position.lat, item.options.position.lng));
+ }
+
+ if (item.options?.title) {
+ opts.title(item.options.title);
+ }
+
+ if (item.options?.snippet) {
+ opts.snippet(item.options.snippet);
+ }
+
+ if (item.options?.icon) {
+ if (item.options?.icon instanceof android.graphics.Bitmap) {
+ const desc = com.google.android.gms.maps.model.BitmapDescriptorFactory.fromBitmap(item.options.icon);
+ opts.icon(desc);
+ } else if (item.options?.icon instanceof ImageSource) {
+ const desc = com.google.android.gms.maps.model.BitmapDescriptorFactory.fromBitmap(item.options.icon.android);
+ opts.icon(desc);
+ }
+ }
+
+ const color = intoNativeColor(item.options.color);
+
+ if (color !== null) {
+ opts.icon(com.google.android.gms.maps.model.BitmapDescriptorFactory.defaultMarker(hueFromColor(color)));
+ }
+
+ if (typeof item.options?.rotation === 'number') {
+ opts.rotation(item.options.rotation);
+ }
+
+ if (typeof item.options?.flat === 'boolean') {
+ opts.flat(item.options.flat);
+ }
+
+ if (typeof item.options?.zIndex === 'number') {
+ opts.zIndex(item.options.zIndex);
+ }
+ }
+}
+
+export class ClusterManager implements IClusterManager {
+ #native: com.google.maps.android.clustering.ClusterManager;
+
+ static fromNative(nativeClusterManager: com.google.maps.android.clustering.ClusterManager) {
+ if (nativeClusterManager instanceof com.google.maps.android.clustering.ClusterManager) {
+ const clusterManager = new ClusterManager();
+ clusterManager.#native = nativeClusterManager;
+ return clusterManager;
+ }
+ return null;
+ }
+
+ private setListeners() {
+ this.#native.setOnClusterClickListener(
+ new com.google.maps.android.clustering.ClusterManager.OnClusterClickListener({
+ onClusterClick: (cluster: com.google.maps.android.clustering.Cluster): boolean => {
+ return false;
+ },
+ })
+ );
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get android() {
+ return this.native;
+ }
+
+ setRenderer(renderer: ClusterRenderer) {
+ this.native.setRenderer(renderer);
+ }
+
+ addItem(clusterItem: ClusterItem) {
+ this.native.addItem(clusterItem);
+ }
+
+ addItems(clusterItems: ClusterItem[]) {
+ const clusterItemArray = new java.util.ArrayList();
+ for (const clusterItem of clusterItems) {
+ clusterItemArray.add(clusterItem);
+ }
+ this.native.addItems(clusterItemArray);
+ }
+
+ removeItem(clusterItem: ClusterItem) {
+ this.native.removeItem(clusterItem);
+ }
+
+ removeItems(clusterItems: ClusterItem[]) {
+ this.native.removeItems(clusterItems as any);
+ }
+
+ clearItems() {
+ this.native.clearItems();
+ }
+
+ cluster() {
+ this.native.cluster();
+ }
+}
+
+/**
+ * EXPERIMENTAL - DO NOT USE
+ */
+export abstract class DataLayer {
+ abstract readonly native: T;
+
+ // setMap(map: com.google.android.gms.maps.GoogleMap) {
+ // this.native.setMap(map);
+ // }
+
+ // getDefaultPolygonStyle() {
+ // return this.native.getDefaultPolygonStyle();
+ // }
+
+ addLayerToMap() {
+ this.native.addLayerToMap();
+ }
+
+ // isLayerOnMap(): boolean {
+ // return this.native.isLayerOnMap();
+ // }
+
+ removeLayerFromMap() {
+ this.native.removeLayerFromMap();
+ }
+
+ // hasFeatures(): boolean {
+ // return this.native.hasFeatures();
+ // }
+
+ // getFeature(feature: any) {
+ // return this.native.getFeature(feature);
+ // }
+
+ // getFeatures(): any {
+ // return this.native.getFeatures();
+ // }
+
+ // addFeature(feature: com.google.maps.android.data.geojson.GeoJsonFeature) {
+ // return this.native.addFeature(feature);
+ // }
+
+ // removeFeature(feature: com.google.maps.android.data.geojson.GeoJsonFeature) {
+ // this.native.removeFeature(feature);
+ // }
+
+ get android() {
+ return this.native;
+ }
+
+ // public hasContainers(): boolean;
+ // public addKMLToMap(): void;
+ // public getDefaultPointStyle(): com.google.maps.android.data.geojson.GeoJsonPointStyle;
+ // public setOnFeatureClickListener(param0: com.google.maps.android.data.Layer.OnFeatureClickListener): void;
+ // public removeFeature(param0: com.google.maps.android.data.Feature): void;
+ // public getMap(): com.google.android.gms.maps.GoogleMap;
+ // public addGeoJsonToMap(): void;
+ // public getDefaultLineStringStyle(): com.google.maps.android.data.geojson.GeoJsonLineStringStyle;
+ // public storeRenderer(param0: com.google.maps.android.data.Renderer): void;
+ // public getContainers(): java.lang.Iterable;
+ // public getContainerFeature(param0: any): com.google.maps.android.data.Feature;
+ // public getGroundOverlays(): java.lang.Iterable;
+}
+
+export class GeoJsonGeometryStyle implements Partial {
+ constructor(private polygonStyle: com.google.maps.android.data.geojson.GeoJsonPolygonStyle, private lineStyle: com.google.maps.android.data.geojson.GeoJsonLineStringStyle, private pointStyle: com.google.maps.android.data.geojson.GeoJsonPointStyle) {}
+
+ get strokeColor() {
+ return new Color(this.polygonStyle.getStrokeColor());
+ }
+ set strokeColor(color: Color) {
+ this.polygonStyle.setStrokeColor(color.android);
+ this.lineStyle.setColor(color.android);
+ }
+
+ get fillColor() {
+ return new Color(this.polygonStyle.getFillColor());
+ }
+ set fillColor(color: Color) {
+ this.polygonStyle.setFillColor(color.android);
+ }
+
+ get width(): number {
+ return this.lineStyle.getWidth();
+ }
+ set width(width: number) {
+ this.lineStyle.setWidth(width);
+ this.polygonStyle.setStrokeWidth(width);
+ }
+
+ get title() {
+ return this.pointStyle.getTitle();
+ }
+ set title(title: string) {
+ this.pointStyle.setTitle(title);
+ }
+
+ get heading(): number {
+ return this.pointStyle.getRotation();
+ }
+ set heading(rotation: number) {
+ // Marker roation or rotation???
+ this.pointStyle.setRotation(rotation);
+ // this.pointStyle.setMarkerRotation(rotation);
+ }
+}
+
+abstract class BaseFeature implements IFeature {
+ abstract style: any;
+ abstract readonly native: T;
+
+ get android() {
+ return this.native;
+ }
+
+ get geometry() {
+ return Geometry.fromNative(this.native.getGeometry());
+ }
+
+ get id() {
+ return this.native.getId();
+ }
+
+ get properties() {
+ const props = {};
+
+ const iter = this.native.getPropertyKeys().iterator();
+ while (iter.hasNext()) {
+ const key = iter.next();
+ props[key] = this.native.getProperty(key);
+ }
+
+ return props;
+ }
+ set properties(value: any) {
+ Object.entries(value).forEach(([key, value]: [string, string]) => {
+ this.native.setProperty(key, value);
+ });
+ }
+}
+
+export class GeoJsonFeature extends BaseFeature {
+ #native: com.google.maps.android.data.geojson.GeoJsonFeature;
+ #style: GeoJsonGeometryStyle;
+
+ constructor() {
+ super();
+ }
+
+ static fromNative(nativeFeature: com.google.maps.android.data.geojson.GeoJsonFeature) {
+ if (nativeFeature instanceof com.google.maps.android.data.geojson.GeoJsonFeature) {
+ const feature = new GeoJsonFeature();
+ feature.#native = nativeFeature;
+ return feature;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get style() {
+ this.#style = new GeoJsonGeometryStyle(this.native.getPolygonStyle(), this.native.getLineStringStyle(), this.native.getPointStyle());
+ return this.#style;
+ }
+}
+
+export class Geometry implements IGeometry {
+ #native: com.google.maps.android.data.Geometry;
+
+ static fromNative(nativeGeometry: com.google.maps.android.data.Geometry) {
+ if (nativeGeometry instanceof com.google.maps.android.data.Geometry) {
+ const geometry = new Geometry();
+ geometry.#native = nativeGeometry;
+ return geometry;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get android() {
+ return this.native;
+ }
+
+ get type() {
+ return this.native.getGeometryType();
+ }
+
+ get geometries() {
+ return this.native.getGeometryObject();
+ }
+}
+
+export class GeoJsonLayer extends DataLayer implements IGeoJsonLayer {
+ #native: com.google.maps.android.data.geojson.GeoJsonLayer;
+ style: GeoJsonGeometryStyle;
+
+ static fromNative(nativeGeoJsonLayer: com.google.maps.android.data.geojson.GeoJsonLayer) {
+ if (nativeGeoJsonLayer instanceof com.google.maps.android.data.geojson.GeoJsonLayer) {
+ const geoJsonLayer = new GeoJsonLayer();
+ geoJsonLayer.#native = nativeGeoJsonLayer;
+ return geoJsonLayer;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get features() {
+ const features: GeoJsonFeature[] = [];
+ const nativeFeatures: java.lang.Iterable = this.native.getFeatures();
+
+ const iter = nativeFeatures.iterator();
+ while (iter.hasNext()) {
+ const feature = iter.next();
+ features.push(GeoJsonFeature.fromNative(feature));
+ }
+
+ return features;
+ }
+
+ // get bounds(): CoordinateBounds {
+ // const bounds = this.#native.getBoundingBox();
+ // if (bounds) {
+ // return {
+ // southwest: {
+ // lat: bounds?.southwest?.latitude,
+ // lng: bounds?.southwest?.longitude,
+ // },
+ // northeast: {
+ // lat: bounds?.northeast?.latitude,
+ // lng: bounds?.northeast?.longitude,
+ // },
+ // };
+ // }
+ // }
+
+ // toString() {
+ // return this.native.toString();
+ // }
+}
diff --git a/packages/google-maps-utils/index.d.ts b/packages/google-maps-utils/index.d.ts
new file mode 100644
index 00000000..a14f4e67
--- /dev/null
+++ b/packages/google-maps-utils/index.d.ts
@@ -0,0 +1,140 @@
+import { Color } from '@nativescript/core';
+import { GoogleMap } from '@nativescript/google-maps';
+
+// export * from './experimental/datalayer';
+// export * from './experimental/iconfactory';
+export * from './utils';
+
+export function installMixins();
+
+declare module '@nativescript/google-maps' {
+ interface GoogleMap {
+ heatmapProvider(options: HeatmapOptions): HeatmapTileProvider;
+ clusterManager(markers: MarkerOptions[]): ClusterManager;
+
+ addGeoJson(geoJson: GeoJSON, styleOptions: IGeometryStyle): GeoJsonLayer;
+ removeGeoJson(geoJsonLayer: GeoJsonLayer): void;
+ }
+}
+
+export class GoogleMapUtils {
+ heatmapProvider(options: HeatmapOptions): HeatmapTileProvider;
+ clusterManager(markers: MarkerOptions[]): ClusterManager;
+
+ addGeoJson(geoJson: GeoJSON, styleOptions: IGeometryStyle): GeoJsonLayer;
+ removeGeoJson(geoJsonLayer: GeoJsonLayer): void;
+}
+
+export interface IGradient {
+ color: Color | string;
+ stop: number;
+}
+
+export interface HeatmapOptions {
+ coordinates: Coordinate[];
+ opacity?: number;
+ radius?: number;
+ maxIntensity?: number;
+ gradient?: IGradient[];
+}
+
+export interface IHeatmapTileProvider {
+ setData: (coordinates: Coordinate[]) => void;
+ setGradient: (gradient: IGradient[]) => void;
+ opacity: number;
+ radius: number;
+ maxIntensity: number;
+}
+
+export class HeatmapTileProvider implements IHeatmapTileProvider {
+ constructor(options: HeatmapOptions);
+ static fromNative: (nativeHeatmap: any) => HeatmapTileProvider;
+ setData: (coordinates: Coordinate[]) => void;
+ setGradient: (gradient: IGradient[]) => void;
+ opacity: number;
+ radius: number;
+ maxIntensity: number;
+ native: any;
+ android: any /*com.google.maps.android.heatmaps.HeatmapTileProvider*/;
+ ios: any /*GMUHeatmapTileLayer*/;
+}
+
+export class ClusterItem {
+ constructor(options: MarkerOptions);
+}
+
+export class ClusterRenderer {
+ constructor(private map: GoogleMap, private manager: ClusterManager);
+ android?: any;
+ ios?: any;
+ native?: any;
+}
+
+export interface IClusterManager {
+ addItems: (clusterItems: ClusterItem[]) => void;
+ addItem: (clusterItem: ClusterItem) => void;
+ removeItems: (clusterItems: ClusterItem[]) => void;
+ removeItem: (clusterItem: ClusterItem) => void;
+ clearItems: () => void;
+ cluster: () => void;
+ setRenderer: (clusterRenderer: any) => void;
+ android?: any;
+ ios?: any;
+ native?: any;
+}
+
+export class ClusterManager implements Partial {
+ onClusterTap(cluster: any) {
+ throw new Error('Method not implemented.');
+ }
+ static fromNative: (nativeClusterManager) => ClusterManager;
+ addItems: (clusterItems: ClusterItem[]) => void;
+ addItem: (clusterItem: ClusterItem) => void;
+ removeItems: (clusterItems: ClusterItem[]) => void;
+ removeItem: (clusterItem: ClusterItem) => void;
+ clearItems: () => void;
+ cluster: () => void;
+ setRenderer: (clusterRenderer: ClusterRenderer) => void;
+ android?: any;
+ ios?: any;
+ native?: any;
+}
+
+export interface IGeoJsonLayer {
+ style: GeometryStyle;
+ addLayerToMap: () => void;
+ removeLayerFromMap: () => void;
+}
+
+export class GeoJsonLayer implements IGeoJsonLayer {
+ ios: any;
+ android: any;
+ native: any;
+ style: GeometryStyle;
+ features: GeoJsonFeature[];
+ constructor(map: GoogleMap, geojson: any, styles?: Partial);
+ addLayerToMap: () => void;
+ removeLayerFromMap: () => void;
+}
+
+export interface IGeometryStyle {
+ strokeColor?: Color;
+ fillColor?: Color;
+ width?: number;
+ scale?: number;
+ heading?: number;
+ anchor?: [number, number];
+ iconUrl?: string | null;
+ title?: string | null;
+}
+
+export interface IGeometry {
+ type: string;
+ geometries: any;
+}
+
+export interface IFeature {
+ geometry: any;
+ properties: any;
+ id: any;
+}
diff --git a/packages/google-maps-utils/index.ios.ts b/packages/google-maps-utils/index.ios.ts
new file mode 100644
index 00000000..b523a374
--- /dev/null
+++ b/packages/google-maps-utils/index.ios.ts
@@ -0,0 +1,356 @@
+import { Color, encoding } from '@nativescript/core';
+import { GeoJSON } from 'geojson';
+import { Coordinate, GoogleMap, ITileProvider, MarkerOptions, intoNativeMarkerOptions } from '@nativescript/google-maps';
+import { HeatmapOptions, IClusterManager, IFeature, IGeoJsonLayer, IGeometry, IGeometryStyle, IGradient, IHeatmapTileProvider, intoNativeClusterManager, intoNativeHeatmapGradient, intoNativeHeatmapProvider } from '.';
+import { applyMixins } from './utils/common';
+
+// export * from './experimental/datalayer';
+// export * from './experimental/iconfactory';
+export * from './utils';
+
+let UNIQUE_STYLE_ID = 0;
+
+let mixinInstalled = false;
+export function overrideGoogleMap() {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ const GMap = require('@nativescript/google-maps').GoogleMap;
+ applyMixins(GMap, [GoogleMapUtils], { after: true });
+}
+
+export function installMixins() {
+ if (!mixinInstalled) {
+ mixinInstalled = true;
+ overrideGoogleMap();
+ }
+}
+
+export class GoogleMapUtils {
+ clusterManager(markers: MarkerOptions[]) {
+ const clusterManager = ClusterManager.fromNative(intoNativeClusterManager(this as unknown as GoogleMap));
+
+ const clusters = markers.map((marker) => new ClusterItem(marker));
+ clusterManager.addItems(clusters);
+
+ clusterManager.cluster();
+
+ return clusterManager;
+ }
+
+ addGeoJson(geoJson: GeoJSON, styleOptions: IGeometryStyle) {
+ if ((this as unknown as GoogleMap) && geoJson) {
+ const style = new GeometryStyle(styleOptions);
+
+ const jsonString = new NSString({ UTF8String: JSON.stringify(geoJson) });
+ const parser = new GMUGeoJSONParser({ data: jsonString.dataUsingEncoding(encoding.UTF_8) });
+ parser.parse();
+
+ const features = parser.features;
+ for (const feature of features) {
+ feature.style = style.native;
+ }
+
+ const renderer = new GMUGeometryRenderer({ map: (this as unknown as GoogleMap).native, geometries: features });
+
+ const layer = GeoJsonLayer.fromNative(renderer);
+
+ layer.addLayerToMap();
+
+ return layer;
+ }
+ return null;
+ }
+
+ removeGeoJson(geoJson: GeoJsonLayer) {
+ if (geoJson) {
+ geoJson.removeLayerFromMap();
+ }
+ }
+}
+
+export class HeatmapTileProvider implements ITileProvider, IHeatmapTileProvider {
+ #native: GMUHeatmapTileLayer;
+
+ constructor(options?: HeatmapOptions) {
+ this.#native = intoNativeHeatmapProvider(options);
+ }
+
+ static fromNative(nativeHeatmap: GMUHeatmapTileLayer) {
+ if (nativeHeatmap instanceof GMUHeatmapTileLayer) {
+ const heatmapTileProvider = new HeatmapTileProvider();
+ heatmapTileProvider.#native = nativeHeatmap;
+ return heatmapTileProvider;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ set opacity(opacity: number) {
+ this.native.opacity = opacity;
+ }
+
+ setGradient(gradients: IGradient[]): void {
+ this.native.gradient = intoNativeHeatmapGradient(gradients);
+ }
+
+ set radius(radius: number) {
+ this.native.radius = radius;
+ }
+
+ set maxIntensity(maxIntensity: number) {
+ this.native.maximumZoomIntensity = maxIntensity;
+ }
+
+ setData(coordinates: Coordinate[]): void {
+ this.native.weightedData = coordinates.map((coordinate) => {
+ return GMUWeightedLatLng.alloc().initWithCoordinateIntensity(CLLocationCoordinate2DMake(coordinate.lat, coordinate.lng), 1.0);
+ }) as any;
+ }
+
+ getTile(x: number, y: number, z: number): UIImage {
+ return this.native.tileForXYZoom(x, y, z);
+ }
+}
+
+export class ClusterItem {
+ #native: GMSMarker;
+
+ constructor(options: MarkerOptions) {
+ this.#native = intoNativeMarkerOptions(options);
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get ios() {
+ return this.native;
+ }
+}
+
+export class ClusterRenderer {
+ #native: GMUClusterRenderer;
+
+ constructor(map: GoogleMap, clusterManager: ClusterManager) {
+ const iconGenerator = GMUDefaultClusterIconGenerator.alloc().init();
+ this.#native = GMUDefaultClusterRenderer.alloc().initWithMapViewClusterIconGenerator(map.native, iconGenerator);
+ }
+
+ get native() {
+ return this.#native;
+ }
+}
+
+export class ClusterManager implements Partial {
+ #native: GMUClusterManager;
+
+ static fromNative(nativeClusterManager: GMUClusterManager) {
+ if (nativeClusterManager instanceof GMUClusterManager) {
+ const clusterManager = new ClusterManager();
+ clusterManager.#native = nativeClusterManager;
+ return clusterManager;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get ios() {
+ return this.#native;
+ }
+
+ setRenderer(renderer) {
+ // TODO;
+ }
+
+ addItem(clusterItem: ClusterItem) {
+ this.native.addItem(clusterItem.native);
+ }
+
+ addItems(clusterItems: ClusterItem[]) {
+ this.native.addItems(clusterItems.map((item) => item.native));
+ }
+
+ removeItem(clusterItem: ClusterItem) {
+ this.native.removeItem(clusterItem.native);
+ }
+
+ removeItems(clusterItems: ClusterItem[]) {
+ clusterItems.forEach((item) => {
+ this.native.removeItem(item.native);
+ });
+ }
+
+ clearItems() {
+ this.native.clearItems();
+ }
+
+ cluster() {
+ this.native.cluster();
+ }
+}
+
+export class GeometryStyle implements IGeometryStyle {
+ #native: GMUStyle;
+
+ constructor(public geometryStyles: Partial) {
+ Object.assign(this, geometryStyles);
+
+ this.#native = new GMUStyle({
+ styleID: `google-maps-utils-style-${UNIQUE_STYLE_ID++}`,
+ strokeColor: this.strokeColor?.ios ?? null,
+ fillColor: this.fillColor?.ios ?? null,
+ width: this.width ?? 1,
+ scale: this.scale ?? 0,
+ heading: this.heading ?? 0,
+ anchor: CGPointMake(this.anchor?.[0] ?? 0, this.anchor?.[1] ?? 0),
+ iconUrl: this.iconUrl ?? null,
+ title: this.title ?? null,
+ hasFill: !!this.fillColor,
+ hasStroke: !!this.strokeColor,
+ } as any);
+ }
+
+ strokeColor: Color;
+ fillColor: Color;
+ width: number;
+ scale: number;
+ heading: number;
+ anchor: [number, number];
+ iconUrl: string;
+ title: string;
+
+ get native() {
+ return this.#native;
+ }
+}
+
+export class GeoJsonLayer implements IGeoJsonLayer {
+ #native: GMUGeometryRenderer;
+ // #parser: GMUGeoJSONParser;
+ style: GeometryStyle;
+
+ // constructor(private map: GoogleMap, private geometries: any, private styles?: Partial) {
+ // this.style = new GeometryStyle(styles);
+
+ // const jsonString = new NSString({ UTF8String: JSON.stringify(geometries) });
+ // this.#parser = new GMUGeoJSONParser({ data: jsonString.dataUsingEncoding(encoding.UTF_8) });
+ // this.#parser.parse();
+
+ // const features = this.#parser.features;
+ // for (const feature of features) {
+ // feature.style = this.style.native;
+ // }
+
+ // this.#native = new GMUGeometryRenderer({ map: this.map.native, geometries: features });
+ // }
+
+ static fromNative(nativeGeoJsonLayer: GMUGeometryRenderer) {
+ if (nativeGeoJsonLayer instanceof GMUGeometryRenderer) {
+ const geoJsonLayer = new GeoJsonLayer();
+ geoJsonLayer.#native = nativeGeoJsonLayer;
+ return geoJsonLayer;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get ios() {
+ return this.native;
+ }
+
+ get features() {
+ // const features = [];
+ // for (const feature of this.#parser.features) {
+ // const f = feature as GMUGeometryContainer;
+
+ // GeoJsonFeature.fromNative(f);
+ // f.geometry;
+ // f.style;
+ // }
+ return null;
+ }
+
+ addLayerToMap() {
+ this.native.render();
+ }
+
+ removeLayerFromMap() {
+ this.native.clear();
+ }
+}
+
+export class GeoJsonFeature implements IFeature {
+ #native: GMUGeometryCollection;
+
+ static fromNative(nativeGeometryContainer: GMUGeometryCollection) {
+ if (nativeGeometryContainer instanceof GMUGeometryCollection) {
+ const geoJsonFeature = new GeoJsonFeature();
+ geoJsonFeature.#native = nativeGeometryContainer;
+ return geoJsonFeature;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get ios() {
+ return this.#native;
+ }
+
+ get geometry() {
+ const geometries = [];
+
+ for (const geometry of this.native.geometries) {
+ geometries.push(Geometry.fromNative(geometry));
+ }
+
+ return geometries;
+ }
+
+ get properties() {
+ return;
+ }
+
+ get id() {
+ return this.native.description;
+ }
+}
+
+export class Geometry implements IGeometry {
+ #native: GMUGeometry;
+
+ static fromNative(nativeGeometry: GMUGeometry) {
+ if (nativeGeometry) {
+ const geometry = new Geometry();
+ geometry.#native = nativeGeometry;
+ return geometry;
+ }
+ return null;
+ }
+
+ get native() {
+ return this.#native;
+ }
+
+ get ios() {
+ return this.#native;
+ }
+
+ get type() {
+ return this.#native.type;
+ }
+
+ get geometries() {
+ return this.native;
+ }
+}
diff --git a/packages/google-maps-utils/package.json b/packages/google-maps-utils/package.json
new file mode 100644
index 00000000..ad0e4708
--- /dev/null
+++ b/packages/google-maps-utils/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "@nativescript/google-maps-utils",
+ "version": "1.0.0",
+ "description": "Add a plugin description",
+ "main": "index",
+ "typings": "index.d.ts",
+ "nativescript": {
+ "platforms": {
+ "ios": "6.0.0",
+ "android": "6.0.0"
+ }
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/NativeScript/plugins.git"
+ },
+ "keywords": [
+ "NativeScript",
+ "JavaScript",
+ "TypeScript",
+ "iOS",
+ "Android"
+ ],
+ "devDependencies": {
+ "@types/geojson": "^7946.0.7"
+ },
+ "author": {
+ "name": "NativeScript",
+ "email": "oss@nativescript.org"
+ },
+ "bugs": {
+ "url": "https://github.com/NativeScript/plugins/issues"
+ },
+ "license": "Apache-2.0",
+ "homepage": "https://github.com/NativeScript/plugins",
+ "readmeFilename": "README.md",
+ "bootstrapper": "@nativescript/plugin-seed"
+}
diff --git a/packages/google-maps-utils/platforms/android/include.gradle b/packages/google-maps-utils/platforms/android/include.gradle
new file mode 100644
index 00000000..60aa0250
--- /dev/null
+++ b/packages/google-maps-utils/platforms/android/include.gradle
@@ -0,0 +1,3 @@
+dependencies {
+ implementation 'com.google.maps.android:android-maps-utils:3.4.0'
+}
diff --git a/packages/google-maps-utils/platforms/ios/Podfile b/packages/google-maps-utils/platforms/ios/Podfile
new file mode 100644
index 00000000..beb91951
--- /dev/null
+++ b/packages/google-maps-utils/platforms/ios/Podfile
@@ -0,0 +1 @@
+pod 'Google-Maps-iOS-Utils', '4.1.0'
diff --git a/packages/google-maps-utils/project.json b/packages/google-maps-utils/project.json
new file mode 100644
index 00000000..a27a83ab
--- /dev/null
+++ b/packages/google-maps-utils/project.json
@@ -0,0 +1,72 @@
+{
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "library",
+ "sourceRoot": "packages/google-maps-utils",
+ "targets": {
+ "build": {
+ "executor": "@nrwl/js:tsc",
+ "options": {
+ "outputPath": "dist/packages/google-maps-utils",
+ "tsConfig": "packages/google-maps-utils/tsconfig.json",
+ "packageJson": "packages/google-maps-utils/package.json",
+ "main": "packages/google-maps-utils/index.d.ts",
+ "assets": [
+ "packages/google-maps-utils/*.md",
+ "packages/google-maps-utils/index.d.ts",
+ "LICENSE",
+ {
+ "glob": "**/*",
+ "input": "packages/google-maps-utils/platforms/",
+ "output": "./platforms/"
+ }
+ ],
+ "dependsOn": [
+ {
+ "target": "build.all",
+ "projects": "dependencies"
+ }
+ ]
+ }
+ },
+ "build.all": {
+ "executor": "@nrwl/workspace:run-commands",
+ "options": {
+ "commands": [
+ "node tools/scripts/build-finish.ts google-maps-utils"
+ ],
+ "parallel": false
+ },
+ "outputs": [
+ "dist/packages/google-maps-utils"
+ ],
+ "dependsOn": [
+ {
+ "target": "build.all",
+ "projects": "dependencies"
+ },
+ {
+ "target": "build",
+ "projects": "self"
+ }
+ ]
+ },
+ "focus": {
+ "executor": "@nrwl/workspace:run-commands",
+ "options": {
+ "commands": [
+ "nx g @nativescript/plugin-tools:focus-packages google-maps-utils,google-maps"
+ ],
+ "parallel": false
+ }
+ },
+ "lint": {
+ "executor": "@nrwl/linter:eslint",
+ "options": {
+ "lintFilePatterns": [
+ "packages/google-maps-utils/**/*.ts"
+ ]
+ }
+ }
+ },
+ "tags": []
+}
diff --git a/packages/google-maps-utils/references.d.ts b/packages/google-maps-utils/references.d.ts
new file mode 100644
index 00000000..548604ba
--- /dev/null
+++ b/packages/google-maps-utils/references.d.ts
@@ -0,0 +1,2 @@
+///
+///
diff --git a/packages/google-maps-utils/tsconfig.json b/packages/google-maps-utils/tsconfig.json
new file mode 100644
index 00000000..aed7323d
--- /dev/null
+++ b/packages/google-maps-utils/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "rootDir": "."
+ },
+ "exclude": ["**/*.spec.ts", "**/*.test.ts", "angular"],
+ "include": ["**/*.ts", "references.d.ts"]
+}
diff --git a/packages/google-maps-utils/typings/android.d.ts b/packages/google-maps-utils/typings/android.d.ts
new file mode 100644
index 00000000..855fb053
--- /dev/null
+++ b/packages/google-maps-utils/typings/android.d.ts
@@ -0,0 +1,8749 @@
+///
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export class BuildConfig {
+ public static class: java.lang.Class;
+ public static DEBUG: boolean;
+ public static LIBRARY_PACKAGE_NAME: string;
+ public static BUILD_TYPE: string;
+ public static TRAVIS: string;
+ public constructor();
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export class MathUtil {
+ public static class: java.lang.Class;
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export class PolyUtil {
+ public static class: java.lang.Class;
+ public static DEFAULT_TOLERANCE: number;
+ public static distanceToLine(param0: com.google.android.gms.maps.model.LatLng, param1: com.google.android.gms.maps.model.LatLng, param2: com.google.android.gms.maps.model.LatLng): number;
+ public static isLocationOnEdge(param0: com.google.android.gms.maps.model.LatLng, param1: java.util.List, param2: boolean): boolean;
+ public static isLocationOnEdge(param0: com.google.android.gms.maps.model.LatLng, param1: java.util.List, param2: boolean, param3: number): boolean;
+ public static locationIndexOnPath(param0: com.google.android.gms.maps.model.LatLng, param1: java.util.List, param2: boolean, param3: number): number;
+ public static isClosedPolygon(param0: java.util.List): boolean;
+ public static locationIndexOnPath(param0: com.google.android.gms.maps.model.LatLng, param1: java.util.List, param2: boolean): number;
+ public static isLocationOnPath(param0: com.google.android.gms.maps.model.LatLng, param1: java.util.List, param2: boolean): boolean;
+ public static containsLocation(param0: com.google.android.gms.maps.model.LatLng, param1: java.util.List, param2: boolean): boolean;
+ public static isLocationOnPath(param0: com.google.android.gms.maps.model.LatLng, param1: java.util.List, param2: boolean, param3: number): boolean;
+ public static locationIndexOnEdgeOrPath(param0: com.google.android.gms.maps.model.LatLng, param1: java.util.List, param2: boolean, param3: boolean, param4: number): number;
+ public static containsLocation(param0: number, param1: number, param2: java.util.List, param3: boolean): boolean;
+ public static decode(param0: string): java.util.List;
+ public static simplify(param0: java.util.List, param1: number): java.util.List;
+ public static encode(param0: java.util.List): string;
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export class SphericalUtil {
+ public static class: java.lang.Class;
+ public static computeArea(param0: java.util.List): number;
+ public static computeSignedArea(param0: java.util.List): number;
+ public static computeOffset(param0: com.google.android.gms.maps.model.LatLng, param1: number, param2: number): com.google.android.gms.maps.model.LatLng;
+ public static computeLength(param0: java.util.List): number;
+ public static interpolate(param0: com.google.android.gms.maps.model.LatLng, param1: com.google.android.gms.maps.model.LatLng, param2: number): com.google.android.gms.maps.model.LatLng;
+ public static computeHeading(param0: com.google.android.gms.maps.model.LatLng, param1: com.google.android.gms.maps.model.LatLng): number;
+ public static computeDistanceBetween(param0: com.google.android.gms.maps.model.LatLng, param1: com.google.android.gms.maps.model.LatLng): number;
+ public static computeOffsetOrigin(param0: com.google.android.gms.maps.model.LatLng, param1: number, param2: number): com.google.android.gms.maps.model.LatLng;
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export class Cluster extends java.lang.Object {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.Cluster interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: { getPosition(): com.google.android.gms.maps.model.LatLng; getItems(): java.util.Collection; getSize(): number });
+ public constructor();
+ public getSize(): number;
+ public getPosition(): com.google.android.gms.maps.model.LatLng;
+ public getItems(): java.util.Collection;
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export class ClusterItem {
+ public static class: java.lang.Class;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.ClusterItem interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: { getPosition(): com.google.android.gms.maps.model.LatLng; getTitle(): string; getSnippet(): string; getZIndex(): java.lang.Float });
+ public constructor();
+ public getZIndex(): java.lang.Float;
+ public getPosition(): com.google.android.gms.maps.model.LatLng;
+ public getSnippet(): string;
+ public getTitle(): string;
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export class ClusterManager extends java.lang.Object {
+ public static class: java.lang.Class>;
+ public setOnClusterItemInfoWindowClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemInfoWindowClickListener): void;
+ public updateItem(param0: T): boolean;
+ public removeItems(param0: java.util.Collection): boolean;
+ public setAlgorithm(param0: com.google.maps.android.clustering.algo.ScreenBasedAlgorithm): void;
+ public setAnimation(param0: boolean): void;
+ public getRenderer(): com.google.maps.android.clustering.view.ClusterRenderer;
+ public getAlgorithm(): com.google.maps.android.clustering.algo.Algorithm;
+ public setOnClusterInfoWindowLongClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterInfoWindowLongClickListener): void;
+ public setAlgorithm(param0: com.google.maps.android.clustering.algo.Algorithm): void;
+ public onInfoWindowClick(param0: com.google.android.gms.maps.model.Marker): void;
+ public getClusterMarkerCollection(): com.google.maps.android.collections.MarkerManager.Collection;
+ public setOnClusterItemClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemClickListener): void;
+ public onMarkerClick(param0: com.google.android.gms.maps.model.Marker): boolean;
+ public constructor(param0: globalAndroid.content.Context, param1: com.google.android.gms.maps.GoogleMap);
+ public clearItems(): void;
+ public setOnClusterInfoWindowClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterInfoWindowClickListener): void;
+ public setOnClusterItemInfoWindowLongClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemInfoWindowLongClickListener): void;
+ public constructor(param0: globalAndroid.content.Context, param1: com.google.android.gms.maps.GoogleMap, param2: com.google.maps.android.collections.MarkerManager);
+ public setOnClusterClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterClickListener): void;
+ public addItems(param0: java.util.Collection): boolean;
+ public addItem(param0: T): boolean;
+ public onCameraIdle(): void;
+ public cluster(): void;
+ public setRenderer(param0: com.google.maps.android.clustering.view.ClusterRenderer): void;
+ public removeItem(param0: T): boolean;
+ public getMarkerCollection(): com.google.maps.android.collections.MarkerManager.Collection;
+ public getMarkerManager(): com.google.maps.android.collections.MarkerManager;
+ }
+ export module ClusterManager {
+ export class ClusterTask extends globalAndroid.os.AsyncTask> {
+ public static class: java.lang.Class;
+ public doInBackground(param0: androidNative.Array): java.util.Set;
+ public onPostExecute(param0: java.util.Set): void;
+ }
+ export class OnClusterClickListener extends java.lang.Object {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.ClusterManager$OnClusterClickListener interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: { onClusterClick(param0: com.google.maps.android.clustering.Cluster): boolean });
+ public constructor();
+ public onClusterClick(param0: com.google.maps.android.clustering.Cluster): boolean;
+ }
+ export class OnClusterInfoWindowClickListener extends java.lang.Object {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.ClusterManager$OnClusterInfoWindowClickListener interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: { onClusterInfoWindowClick(param0: com.google.maps.android.clustering.Cluster): void });
+ public constructor();
+ public onClusterInfoWindowClick(param0: com.google.maps.android.clustering.Cluster): void;
+ }
+ export class OnClusterInfoWindowLongClickListener extends java.lang.Object {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.ClusterManager$OnClusterInfoWindowLongClickListener interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: { onClusterInfoWindowLongClick(param0: com.google.maps.android.clustering.Cluster): void });
+ public constructor();
+ public onClusterInfoWindowLongClick(param0: com.google.maps.android.clustering.Cluster): void;
+ }
+ export class OnClusterItemClickListener extends java.lang.Object {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.ClusterManager$OnClusterItemClickListener interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: { onClusterItemClick(param0: T): boolean });
+ public constructor();
+ public onClusterItemClick(param0: T): boolean;
+ }
+ export class OnClusterItemInfoWindowClickListener extends java.lang.Object {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.ClusterManager$OnClusterItemInfoWindowClickListener interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: { onClusterItemInfoWindowClick(param0: T): void });
+ public constructor();
+ public onClusterItemInfoWindowClick(param0: T): void;
+ }
+ export class OnClusterItemInfoWindowLongClickListener extends java.lang.Object {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.ClusterManager$OnClusterItemInfoWindowLongClickListener interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: { onClusterItemInfoWindowLongClick(param0: T): void });
+ public constructor();
+ public onClusterItemInfoWindowLongClick(param0: T): void;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module algo {
+ export abstract class AbstractAlgorithm extends com.google.maps.android.clustering.algo.Algorithm {
+ public static class: java.lang.Class>;
+ public constructor();
+ public addItems(param0: java.util.Collection): boolean;
+ public setMaxDistanceBetweenClusteredItems(param0: number): void;
+ public getClusters(param0: number): java.util.Set;
+ public unlock(): void;
+ public addItem(param0: any): boolean;
+ public removeItem(param0: any): boolean;
+ public getItems(): java.util.Collection;
+ public clearItems(): void;
+ public lock(): void;
+ public updateItem(param0: any): boolean;
+ public getMaxDistanceBetweenClusteredItems(): number;
+ public removeItems(param0: java.util.Collection): boolean;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module algo {
+ export class Algorithm extends java.lang.Object {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.algo.Algorithm interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: { addItem(param0: T): boolean; addItems(param0: java.util.Collection): boolean; clearItems(): void; removeItem(param0: T): boolean; updateItem(param0: T): boolean; removeItems(param0: java.util.Collection): boolean; getClusters(param0: number): java.util.Set; getItems(): java.util.Collection; setMaxDistanceBetweenClusteredItems(param0: number): void; getMaxDistanceBetweenClusteredItems(): number; lock(): void; unlock(): void });
+ public constructor();
+ public addItem(param0: T): boolean;
+ public updateItem(param0: T): boolean;
+ public addItems(param0: java.util.Collection): boolean;
+ public clearItems(): void;
+ public setMaxDistanceBetweenClusteredItems(param0: number): void;
+ public lock(): void;
+ public getClusters(param0: number): java.util.Set;
+ public removeItem(param0: T): boolean;
+ public getMaxDistanceBetweenClusteredItems(): number;
+ public unlock(): void;
+ public removeItems(param0: java.util.Collection): boolean;
+ public getItems(): java.util.Collection;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module algo {
+ export class GridBasedAlgorithm extends com.google.maps.android.clustering.algo.AbstractAlgorithm {
+ public static class: java.lang.Class>;
+ public constructor();
+ public addItems(param0: java.util.Collection): boolean;
+ public setMaxDistanceBetweenClusteredItems(param0: number): void;
+ public getClusters(param0: number): java.util.Set;
+ public addItem(param0: any): boolean;
+ public unlock(): void;
+ public removeItem(param0: any): boolean;
+ public getItems(): java.util.Collection;
+ public clearItems(): void;
+ public lock(): void;
+ public updateItem(param0: any): boolean;
+ public getMaxDistanceBetweenClusteredItems(): number;
+ public removeItems(param0: java.util.Collection): boolean;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module algo {
+ export class NonHierarchicalDistanceBasedAlgorithm extends com.google.maps.android.clustering.algo.AbstractAlgorithm {
+ public static class: java.lang.Class>;
+ public constructor();
+ public addItems(param0: java.util.Collection): boolean;
+ public getClusteringItems(param0: com.google.maps.android.quadtree.PointQuadTree>, param1: number): java.util.Collection>;
+ public setMaxDistanceBetweenClusteredItems(param0: number): void;
+ public getClusters(param0: number): java.util.Set;
+ public addItem(param0: any): boolean;
+ public unlock(): void;
+ public removeItem(param0: any): boolean;
+ public getItems(): java.util.Collection;
+ public clearItems(): void;
+ public lock(): void;
+ public updateItem(param0: any): boolean;
+ public getMaxDistanceBetweenClusteredItems(): number;
+ public removeItems(param0: java.util.Collection): boolean;
+ }
+ export module NonHierarchicalDistanceBasedAlgorithm {
+ export class QuadItem extends java.lang.Object {
+ public static class: java.lang.Class>;
+ public getItems(): java.util.Set;
+ public equals(param0: any): boolean;
+ public getPoint(): com.google.maps.android.geometry.Point;
+ public getItems(): java.util.Collection;
+ public getSize(): number;
+ public hashCode(): number;
+ public getPosition(): com.google.android.gms.maps.model.LatLng;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module algo {
+ export class NonHierarchicalViewBasedAlgorithm extends com.google.maps.android.clustering.algo.NonHierarchicalDistanceBasedAlgorithm implements com.google.maps.android.clustering.algo.ScreenBasedAlgorithm {
+ public static class: java.lang.Class>;
+ public constructor();
+ public addItems(param0: java.util.Collection): boolean;
+ public constructor(param0: number, param1: number);
+ public getClusteringItems(param0: com.google.maps.android.quadtree.PointQuadTree>, param1: number): java.util.Collection>;
+ public setMaxDistanceBetweenClusteredItems(param0: number): void;
+ public getClusters(param0: number): java.util.Set;
+ public onCameraChange(param0: com.google.android.gms.maps.model.CameraPosition): void;
+ public addItem(param0: any): boolean;
+ public unlock(): void;
+ public updateViewSize(param0: number, param1: number): void;
+ public removeItem(param0: any): boolean;
+ public getItems(): java.util.Collection;
+ public clearItems(): void;
+ public lock(): void;
+ public shouldReclusterOnMapMovement(): boolean;
+ public updateItem(param0: any): boolean;
+ public getMaxDistanceBetweenClusteredItems(): number;
+ public removeItems(param0: java.util.Collection): boolean;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module algo {
+ export class PreCachingAlgorithmDecorator extends com.google.maps.android.clustering.algo.AbstractAlgorithm {
+ public static class: java.lang.Class>;
+ public constructor();
+ public addItems(param0: java.util.Collection): boolean;
+ public setMaxDistanceBetweenClusteredItems(param0: number): void;
+ public constructor(param0: com.google.maps.android.clustering.algo.Algorithm);
+ public getClusters(param0: number): java.util.Set;
+ public addItem(param0: any): boolean;
+ public unlock(): void;
+ public removeItem(param0: any): boolean;
+ public getItems(): java.util.Collection;
+ public clearItems(): void;
+ public lock(): void;
+ public updateItem(param0: any): boolean;
+ public getMaxDistanceBetweenClusteredItems(): number;
+ public removeItems(param0: java.util.Collection): boolean;
+ }
+ export module PreCachingAlgorithmDecorator {
+ export class PrecacheRunnable {
+ public static class: java.lang.Class;
+ public constructor(param0: com.google.maps.android.clustering.algo.PreCachingAlgorithmDecorator, param1: number);
+ public run(): void;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module algo {
+ export class ScreenBasedAlgorithm extends com.google.maps.android.clustering.algo.Algorithm {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.algo.ScreenBasedAlgorithm interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: {
+ shouldReclusterOnMapMovement(): boolean;
+ onCameraChange(param0: com.google.android.gms.maps.model.CameraPosition): void;
+ addItem(param0: any): boolean;
+ addItems(param0: java.util.Collection): boolean;
+ clearItems(): void;
+ removeItem(param0: any): boolean;
+ updateItem(param0: any): boolean;
+ removeItems(param0: java.util.Collection): boolean;
+ getClusters(param0: number): java.util.Set;
+ getItems(): java.util.Collection;
+ setMaxDistanceBetweenClusteredItems(param0: number): void;
+ getMaxDistanceBetweenClusteredItems(): number;
+ lock(): void;
+ unlock(): void;
+ });
+ public constructor();
+ public addItems(param0: java.util.Collection): boolean;
+ public setMaxDistanceBetweenClusteredItems(param0: number): void;
+ public getClusters(param0: number): java.util.Set;
+ public onCameraChange(param0: com.google.android.gms.maps.model.CameraPosition): void;
+ public addItem(param0: any): boolean;
+ public unlock(): void;
+ public removeItem(param0: any): boolean;
+ public getItems(): java.util.Collection;
+ public clearItems(): void;
+ public lock(): void;
+ public shouldReclusterOnMapMovement(): boolean;
+ public updateItem(param0: any): boolean;
+ public getMaxDistanceBetweenClusteredItems(): number;
+ public removeItems(param0: java.util.Collection): boolean;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module algo {
+ export class ScreenBasedAlgorithmAdapter extends com.google.maps.android.clustering.algo.AbstractAlgorithm implements com.google.maps.android.clustering.algo.ScreenBasedAlgorithm {
+ public static class: java.lang.Class>;
+ public constructor();
+ public addItems(param0: java.util.Collection): boolean;
+ public setMaxDistanceBetweenClusteredItems(param0: number): void;
+ public constructor(param0: com.google.maps.android.clustering.algo.Algorithm);
+ public getClusters(param0: number): java.util.Set;
+ public addItem(param0: any): boolean;
+ public onCameraChange(param0: com.google.android.gms.maps.model.CameraPosition): void;
+ public unlock(): void;
+ public removeItem(param0: any): boolean;
+ public getItems(): java.util.Collection;
+ public clearItems(): void;
+ public lock(): void;
+ public shouldReclusterOnMapMovement(): boolean;
+ public updateItem(param0: any): boolean;
+ public getMaxDistanceBetweenClusteredItems(): number;
+ public removeItems(param0: java.util.Collection): boolean;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module algo {
+ export class StaticCluster extends com.google.maps.android.clustering.Cluster {
+ public static class: java.lang.Class>;
+ public add(param0: any): boolean;
+ public getSize(): number;
+ public hashCode(): number;
+ public remove(param0: any): boolean;
+ public constructor(param0: com.google.android.gms.maps.model.LatLng);
+ public getPosition(): com.google.android.gms.maps.model.LatLng;
+ public toString(): string;
+ public equals(param0: any): boolean;
+ public getItems(): java.util.Collection;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module view {
+ export class ClusterRenderer extends java.lang.Object {
+ public static class: java.lang.Class>;
+ /**
+ * Constructs a new instance of the com.google.maps.android.clustering.view.ClusterRenderer interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
+ */
+ public constructor(implementation: {
+ onClustersChanged(param0: java.util.Set): void;
+ setOnClusterClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterClickListener): void;
+ setOnClusterInfoWindowClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterInfoWindowClickListener): void;
+ setOnClusterInfoWindowLongClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterInfoWindowLongClickListener): void;
+ setOnClusterItemClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemClickListener): void;
+ setOnClusterItemInfoWindowClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemInfoWindowClickListener): void;
+ setOnClusterItemInfoWindowLongClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemInfoWindowLongClickListener): void;
+ setAnimation(param0: boolean): void;
+ setAnimationDuration(param0: number): void;
+ onAdd(): void;
+ onRemove(): void;
+ getColor(param0: number): number;
+ getClusterTextAppearance(param0: number): number;
+ });
+ public constructor();
+ public setOnClusterItemInfoWindowLongClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemInfoWindowLongClickListener): void;
+ public onClustersChanged(param0: java.util.Set): void;
+ public setOnClusterInfoWindowLongClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterInfoWindowLongClickListener): void;
+ public setOnClusterItemInfoWindowClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemInfoWindowClickListener): void;
+ public setOnClusterInfoWindowClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterInfoWindowClickListener): void;
+ public setOnClusterItemClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemClickListener): void;
+ public onAdd(): void;
+ public setOnClusterClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterClickListener): void;
+ public getColor(param0: number): number;
+ public onRemove(): void;
+ public setAnimation(param0: boolean): void;
+ public setAnimationDuration(param0: number): void;
+ public getClusterTextAppearance(param0: number): number;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+declare module com {
+ export module google {
+ export module maps {
+ export module android {
+ export module clustering {
+ export module view {
+ export class DefaultClusterRenderer extends com.google.maps.android.clustering.view.ClusterRenderer {
+ public static class: java.lang.Class>;
+ public onClusterItemUpdated(param0: any, param1: com.google.android.gms.maps.model.Marker): void;
+ public getClusterText(param0: number): string;
+ public getBucket(param0: com.google.maps.android.clustering.Cluster): number;
+ public onClustersChanged(param0: java.util.Set): void;
+ public setOnClusterItemInfoWindowLongClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemInfoWindowLongClickListener): void;
+ public onClusterRendered(param0: com.google.maps.android.clustering.Cluster, param1: com.google.android.gms.maps.model.Marker): void;
+ public onClusterUpdated(param0: com.google.maps.android.clustering.Cluster, param1: com.google.android.gms.maps.model.Marker): void;
+ public setMinClusterSize(param0: number): void;
+ public setOnClusterItemClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemClickListener): void;
+ public getClusterItem(param0: com.google.android.gms.maps.model.Marker): any;
+ public shouldRender(param0: java.util.Set, param1: java.util.Set): boolean;
+ public getColor(param0: number): number;
+ public onBeforeClusterRendered(param0: com.google.maps.android.clustering.Cluster, param1: com.google.android.gms.maps.model.MarkerOptions): void;
+ public onRemove(): void;
+ public setAnimation(param0: boolean): void;
+ public getMarker(param0: com.google.maps.android.clustering.Cluster): com.google.android.gms.maps.model.Marker;
+ public getDescriptorForCluster(param0: com.google.maps.android.clustering.Cluster): com.google.android.gms.maps.model.BitmapDescriptor;
+ public getMinClusterSize(): number;
+ public constructor(param0: globalAndroid.content.Context, param1: com.google.android.gms.maps.GoogleMap, param2: com.google.maps.android.clustering.ClusterManager);
+ public getClusterTextAppearance(param0: number): number;
+ public setOnClusterInfoWindowClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterInfoWindowClickListener): void;
+ public setOnClusterClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterClickListener): void;
+ public onBeforeClusterItemRendered(param0: any, param1: com.google.android.gms.maps.model.MarkerOptions): void;
+ public setOnClusterInfoWindowLongClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterInfoWindowLongClickListener): void;
+ public onAdd(): void;
+ public setOnClusterItemInfoWindowClickListener(param0: com.google.maps.android.clustering.ClusterManager.OnClusterItemInfoWindowClickListener): void;
+ public getCluster(param0: com.google.android.gms.maps.model.Marker): com.google.maps.android.clustering.Cluster