diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6ae867d --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +TODO: place your license here and we'll include it in the module distribution diff --git a/README.md b/README.md new file mode 100644 index 0000000..a1150e6 --- /dev/null +++ b/README.md @@ -0,0 +1,496 @@ +## ti.parselivequery +------------------------ + +```js +import Parse from 'ti.parselivequery'; +``` +------------------------ + +# Version 1.0.0 +#### Module Constants +```js +// use to set/get log-levels +Parse.LOG_LEVEL_DEBUG +Parse.LOG_LEVEL_ERROR +Parse.LOG_LEVEL_INFO +Parse.LOG_LEVEL_VERBOSE +Parse.LOG_LEVEL_WARNING +Parse.LOG_LEVEL_NONE + +// use to set/get cache-policy +Parse.IGNORE_CACHE +Parse.CACHE_ONLY +Parse.NETWORK_ONLY +Parse.CACHE_ELSE_NETWORK +Parse.NETWORK_ELSE_CACHE +Parse.CACHE_THEN_NETWORK + +// use to know query event type in `event` +Parse.EVENT_TYPE_ENTERED +Parse.EVENT_TYPE_LEFT +Parse.EVENT_TYPE_CREATED +Parse.EVENT_TYPE_UPDATED +Parse.EVENT_TYPE_DELETED +``` +------------------------ + +### Common patterns +```js +// All callbacks follow below pattern: +function allCallbacks(e) { + const IMPORTANT_MESSAGE = 'e.success: this will be `true` when the operation was successful, otherwise `false`, + e.code: this will be `null` when e.success = true, otherwise will hold an error code from Parse SDK + e.message: error message corresponds to `e.code` above, otherwise empty + ******************************************************************************************* + some callbacks will return extra field to access the required data of that callback + e.g., e.parseFile, e.parseUser, e.parseObject, e.parseObjects, etc... + only this extra field will be mentioned in callbacks in rest of the documentation'; +} +``` +------------------------ + +### Parse +```js +// Always initialize the module before accessing anything +const isInitialized = Parse.initialize({ + appId: '', + clientKey: '', + server: '', + enableLocalStore: true // default `false` +}); + +// Parse methods +Parse.destroyParse(); +Parse.setLogLevel(int logLevel); +Parse.setServer(String url); +Parse.fetchAllInBackground([ParseObject], optional => alert(optional.success)); +Parse.pinAllInBackground([ParseObject], optional => alert(optional.success)); +Parse.pinAllInBackground('key', [ParseObject], optional => alert(optional.success)); +Parse.saveAllInBackground([ParseObject], optional => alert(optional.success)); +Parse.unpinAllInBackground(optional => alert(optional.success)); +Parse.unpinAllInBackground([ParseObject], optional => alert(optional.success)); +Parse.unpinAllInBackground('key', optional => alert(optional.success)); +Parse.unpinAllInBackground('key', [ParseObject], optional => alert(optional.success)); +``` + +### Parse Client +```js +// always create a single client for single app session +const Client = Parse.createParseClient(); + +// properties +const isConnected = Client.isConnected; + +// events +Client.addEventListener('clientConnected', e => alert(e.value)); // value: true +Client.addEventListener('clientDisconnected', e => alert(e.value)); // value: true +Client.addEventListener('clientSocketError', e => alert(e.value)); // value: error message +Client.addEventListener('clientError', e => alert(e.value)); // value: error message + +// methods +Client.registerListener(); // this will register & fire above events +Client.unregisterListener(); // this will only unregister above events +Client.reconnectClient(); +Client.reconnectClientIfNeeded(); +Client.disconnectClient(); +Client.destroyClient(); // disconnect client, unregister events and destroy the client instancce +``` + +### Parse Query +```js +// `className` is mandatory here +const Query = Parse.createQuery({ className: 'object-name' }); + +// properties +Query.className; +Query.isRunning; // to check whether this query is already running + + +// events +Query.addEventListener('error', e => alert(e.message)); +Query.addEventListener('subscribe', () => { /* just to know query has been subscribed */ }); +Query.addEventListener('unsubscribe', () => { /* just to know query has been un-subscribed */ }); +Query.addEventListener('event', e => { + // e.parseObject = ParseObject associated with this query + // e.parseEventType = Parse.EVENT_TYPE_CREATED , etc. +}); + + +// methods +Query.subscribe(Client); +Query.unsubscribe(Client); +Query.findInBackground(e => { + // optional callback + // e.parseObjects - array having ParseObject instances +}); +Query.clear('key'); +Query.addAscendingOrder('key'); +Query.cancel(); +Query.clearCachedResult(); +Query.countInBackground(e => { + // optional callback + // e.count - array having ParseObject instances +}); +Query.addDescendingOrder('key'); +Query.fromLocalDatastore(); +Query.fromNetwork(); +Query.fromPin('optional key'); +Query.getCachePolicy(); // returns String +Query.getFirstInBackground(e => { + // optional callback + // e.parseObject - ParseObject instance or null +}); +Query.getInBackground('key', e => { + // optional callback + // e.parseObject - ParseObject instance or null +}); +Query.getLimit(); // returns int +Query.getMaxCacheAge(); // returns int +Query.getSkip(); // returns int +Query.hasCachedResult(); // returns boolean +Query.ignoreACLs(); +Query.include('key'); +Query.orderByAscending('key'); +Query.orderByDescending('key'); +Query.selectKeys(['array of keys']); +Query.setCachePolicy('key'); +Query.setLimit(10); +Query.setMaxCacheAge(10); +Query.setSkip(10); +Query.setTrace(true); +Query.whereContainedIn('key', [1, 'Joseph', {name: 'Prashant Saini'}]); +Query.whereContains('key', 'sub-key'); +Query.whereContainsAll('key', ['array of anything which can be converted to JSON']); +Query.whereContainsAllStartsWith('key', ['array of matching keys']); +Query.whereDoesNotExist('key'); +Query.whereDoesNotMatchKeyInQuery('key', 'key in query', Query); +Query.whereDoesNotMatchQuery('key', Query); +Query.whereEndsWith('key', 'value'); +Query.whereEqualTo('key', anyValueToMatchForKey); +Query.whereExists('key'); +Query.whereFullText('key', 'value'); +Query.whereGreaterThan('key', anyValueToMatchForKey); +Query.whereGreaterThanOrEqualTo('key', anyValueToMatchForKey); +Query.whereLessThan('key', anyValueToMatchForKey); +Query.whereLessThanOrEqualTo('key', anyValueToMatchForKey); +Query.whereMatches('key', 'value'); +Query.whereMatchesKeyInQuery('key', 'key in query', Query); +Query.whereMatchesQuery('key', Query); +Query.whereNotContainedIn('key', ['array of anything which can be converted to JSON']); +Query.whereNotEqualTo('key', anyValueToMatchForKey); +Query.whereStartsWith('key', 'value'); +``` + +### Parse Object +```js +// `className` is mandatory +const ParseObject = Parse.createParseObject({ className: 'object-name' }); + +// properties +ParseObject.className; +ParseObject.isAvailable; // read-only: whether the ParseObject is ready +ParseObject.updatedAt; // read-only: JS Date +ParseObject.createdAt; // read-only: JS Date +ParseObject.objectId; // read-write: String: unique object-id for this object + +// methods +ParseObject.add('key', anyJSONObject); +ParseObject.addUnique('key', anyJSONObject); +ParseObject.containsKey('key'); // returns boolean +ParseObject.deleteEventually(optional => alert(optional.success)); +ParseObject.deleteInBackground(optional => alert(optional.success)); +ParseObject.fetchInBackground(optional => alert(optional.success)); // this will internally update the current ParseObject before firing callback +ParseObject.fetchFromLocalDatastoreInBackground(optional => alert(optional.success)); // this will internally update the current ParseObject before firing callback +ParseObject.fetchIfNeededInBackground(optional => alert(optional.success)); // this will internally update the current ParseObject before firing callback +ParseObject.get('key'); // returns object +ParseObject.getJSONArray('key'); // returns JSON array +ParseObject.getJSONObject('key'); // returns JSON object +ParseObject.has('key'); // returns boolean +ParseObject.hasSameId(ParseObjectProxy); // returns boolean +ParseObject.increment('key', anyOptionalInteger); +ParseObject.isDataAvailable('optional key'); // returns boolean +ParseObject.isDirty('optional key'); // returns boolean +ParseObject.keySet(); // returns String array +ParseObject.pinInBackground(optional => alert(optional.success)); +ParseObject.pinInBackground('key', optional => alert(optional.success)); +ParseObject.put('key', anyJSONObjectOrPrimitiveValue); +ParseObject.remove('key', ['optional array of anything which can be converted to JSON']); +ParseObject.revert('optional key'); +ParseObject.saveEventually(optional => alert(optional.success)); +ParseObject.saveInBackground(optional => alert(optional.success)); +ParseObject.unpinInBackground(optional => alert(optional.success)); +ParseObject.unpinInBackground('key', optional => alert(optional.success)); +``` + +------------------------ + +# Version 1.1.0 +### ParseFile + +```js +const file1 = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, 'textfile.txt'); +const file2 = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, 'image.jpg'); + +// only two parameters are supported - fileName and fileData +// both these parameters can be added/altered at any stage +const parseFile1 = Parse.createParseFile({ + fileName: 'textfile.txt', // file extension must be available + fileData: file1.read() +}); + +// or create ParseFile instance this way +const parseFile2 = Parse.createParseFile(); +parseFile2.fileName = 'image.jpg'; +parseFile2.fileData = file2.read(); + +// once these parameters are set, call invalidate() to internally create ParseFile instance to execute further methods +parseFile1.invalidate(); + +// now we can execute below further methods +parseFile2.cancel(); // Cancels the operations for this {@code ParseFile} if they are still in the task queue. However, if a network request has already been started for an operation, the network request will not be canceled. +parseFile2.getName(); // The filename. Before save is called, this is just the filename given by the user (if any). After save is called, that name gets prefixed with a unique identifier. +parseFile2.getUrl(); // This returns the url of the file. It's only available after you save or after you get the file from a ParseObject. +parseFile2.isDataAvailable(); // Whether the file has available data. +parseFile2.isDirty(); // Whether the file still needs to be saved. + +/** + * Asynchronously gets the data from cache if available or fetches its content from the network. + * Supports below 2 callbacks + * @param dataCallback is called when the get completes. + * @param progressCallback (optional) is called periodically with progress updates. + */ +parseFile2.getDataInBackground(e => { + // Mandatory callback + // e.fileData = Ti.Blob instance, similar to as we passed at creation time +}, e => { + // Optional callback + // e.fileProgress = 0, 1, 2... to 100 (100 guarantees the fetch completion and first callback will be called) +}); + +/** + * Saves the file to the Parse cloud in a background thread. `progressCallback` is guaranteed to + * be called with 100 before saveCallback is called. + * Supports below 2 callbacks + * @param saveCallback gets called when the save completes. + * @param progressCallback is called periodically with progress updates. + * */ +parseFile2.saveDataInBackground(e => { + // optional callback +}, e => { + // Optional callback + // e.fileProgress = 0, 1, 2... to 100 (100 guarantees the fetch completion and first callback will be called) +}); + +// finally you can add ParseFile instance in ParseObject +ParseObject.put('mytextfile', parseFile1); +ParseObject.put('myimagefile', parseFile2); + +// Retrieve ParseFile from ParseObject +const imageParseFile = ParseObject.getParseFile('myimagefile'); +const fileName = imageParseFile.fileName; +let fileData = imageParseFile.fileData; // it will be null until we call `getDataInBackground` + +// no need to call `invalidate()` in this case since we are fetching the ParseFile from server +imageParseFile.getDataInBackground(e => { + // Mandatory callback + // e.fileData = Ti.Blob instance, similar to as we passed at creation time +}); +``` + +### Compound Query + +```js +const query1 = Parse.createQuery({ className: 'object-name1' }); +const query2 = Parse.createQuery({ className: 'object-name2' }); +const query3 = Parse.createQuery({ className: 'object-name3' }); + +// `createCompoundQuery()` needs an array of Query instances +// it will return a new Query instance which you can use further to execute Query class methods listed in v1.0.0 +const compoundQuery = Parse.createCompoundQuery([query1, query2, query3]); +``` + +### ParseGeoPoint, ParsePolygon + +```js +const geoPoint1 = Parse.createParseGeoPoint({ + latitude: -30, // allowed range: -90 < latitude < 90 + longitude: -40.0 // allowed range: -180 < latitude < 180 +}); + +const geoPoint2 = Parse.createParseGeoPoint({ + latitude: 30, + longitude: 40.0 +}); + +const geoPoint3 = Parse.createParseGeoPoint(); +geoPoint3.latitude = 89; +geoPoint3.longitude = 179.0; + +// minimum 3 geo-points are required to create a ParsePolygon instance +const polygon1 = Parse.createParsePolygon({ + parseGeoPointList: [geoPoint1, geoPoint2, geoPoint3] // array of +}); + +polygon.containsPoint(geoPoint2); // true/false: if polygon contains ParseGeoPoint + +// add ParseGeoPoint/ParsePolygon in ParseObject +ParseObject.put('geopoint1', geoPoint1); +ParseObject.put('polygon', polygon); + +// retrieve like this +const geoPointOne = ParseObject.getParseGeoPoint('geopoint1'); +const polygonOne = ParseObject.getParsePolygon('polygon'); + +// GeoQueries +Query.whereNear('location', geoPoint2); +Query.setLimit(10); // max 100 +Query.findInBackground(...); // use findInBackground as already developed in v1.0.0 +Query.whereWithinKilometers('key', geoPoint1, maxDistanceInNumber); +Query.whereWithinMiles('key', geoPoint2, maxDistanceInNumber); +Query.whereWithinRadians('key', geoPoint3, maxDistanceInNumber); +Query.whereWithinGeoBox('key', geoPoint1, geoPoint2); +Query.whereWithinPolygon('key', [geoPoint1, geoPoint2, geoPoint3]); // either array of min 3 ParseGeoPoint +Query.whereWithinPolygon('key', parsePolygonProxy.getParsePolygon()); // or ParsePolygon instance +Query.wherePolygonContains('key', geoPoint2); // polygon.containsPoint(geoPoint2) is more efficient alternate +``` + +### DATA TYPES | Parse.put() & Parse.get methods + +```js +// equivalent put/get methods for currently supported data types +ParseObject.put('key', number); +ParseObject.put('key', string); +ParseObject.put('key', boolean); +ParseObject.put('key', null); +ParseObject.get('key'); // cast to above type in JS + +ParseObject.put('key', [array]); +ParseObject.getJSONArray('key'); + +ParseObject.put('key', {dictionary}); +ParseObject.getJSONObject('key'); + +ParseObject.put('key', ParseObject); // acts as Pointer for other ParseObject +ParseObject.getParseObject('key'); + +ParseObject.put('key', ParseFile); +ParseObject.getParseFile('key'); + +ParseObject.put('key', ParseGeoPoint); +ParseObject.getParseGeoPoint('key'); + +ParseObject.put('key', ParsePolygon); +ParseObject.getParsePolygon('key'); +``` + +### Changes in existing Parse/Query methods +```js +// pass any data type mentioned above in below methods +// all these methods are still backward compatible, they now support more data types +ParseObject.addAll('key', 'array of data-type mentioned above'); +ParseObject.addAllUnique('key', 'array of data-type mentioned above'); +ParseObject.removeAll('key', 'array of data-type mentioned above'); + +Query.whereContainedIn('key', 'array of data-type mentioned above'); +Query.whereContainsAll('key', 'array of data-type mentioned above'); +Query.whereNotContainedIn('key', 'array of data-type mentioned above'); + +Query.whereEqualTo('key', 'data-type mentioned above'); +Query.whereGreaterThan('key', 'data-type mentioned above'); +Query.whereGreaterThanOrEqualTo('key', 'data-type mentioned above'); +Query.whereLessThan('key', 'data-type mentioned above'); +Query.whereLessThanOrEqualTo('key', 'data-type mentioned above'); +Query.whereNotEqualTo('key', 'data-type mentioned above'); +``` + +### ParseUser +##### (subclass of ParseObject, already contains all methods available in ParseObject class) +```js +const parseUser = Parse.createParseUser(); + +parseUser.setUsername('string'); +parseUser.setEmail('string'); +parseUser.setPassword('string'); +parseUser.getUsername(); +parseUser.getEmail(); +parseUser.getSessionToken(); // session token for a user, if they are logged in. + +parseUser.getParseUser('key to retrieve another parseUser as pointers'); + +// Indicates whether this user was created during this session through a call to signUpInBackground +// or by logging in with a linked service such as Facebook. +parseUser.isNew(); + +/** + * Whether the ParseUser has been authenticated on this device. This will be true if the + * ParseUser was obtained via a logIn or signUp method. Only an authenticated ParseUser can be + * saved (with altered attributes) and deleted. + */ +parseUser.isAuthenticated(); + + +/** +* Signs up a new user. You should call this instead of {@link #save} for new ParseUsers. This +* will create a new ParseUser on the server, and also persist the session on disk so that you +* can access the user using {@link #getCurrentUser}. +* +* A username and password must be set before calling signUp. +*/ +parseUser.signUpInBackground(e => { + // optional callback +}); +``` + +#### Methods in Parse.() scope, related to ParseUser instances +```js +// This retrieves the currently logged in ParseUser with a valid session, either from memory or disk if necessary. +Parse.getCurrentUser(); + +/** +* Enables automatic creation of anonymous users. After calling this method, +* getCurrentUser() will always have a value. The user will only be created on the server once +* the user has been saved, or once an object with a relation to that user or an ACL that refers +* to the user has been saved. +*/ +Parse.enableAutomaticUser(); + +// if no ParseUser is passed in arguments, it will consider the Parse.getCurrentUser(); +Parse.isLinked(parseUser); + +// Logs in a user with a username and password. On success, this saves the session to disk, so +// you can retrieve the currently logged in user using {@link #getCurrentUser}. +Parse.loginInBackground('username', 'password', e => { + // Mandatory callback + // e.parseUser = logged-in Parse.createParseUser() instance +}); + +// Logs out the currently logged in user session. This will remove the session from disk, log +//out of linked services, and future calls to getCurrentUser() will be null +Parse.logOutInBackground(e => { + // Mandatory callback + // e.parseUser = null +}); + +// Creates an anonymous user in the background (https://docs.parseplatform.org/android/guide/#anonymous-users) +Parse.anonymousLogIn(e => { + // Mandatory callback + // e.parseUser = anonymous logged-in user +}); + +// Authorize a user with a session token. On success, this saves the session to disk, so you can +// retrieve the currently logged in user using getCurrentUser(). +Parse.becomeInBackground('session-token', e => { + // Mandatory callback + // e.parseUser = logged-in Parse.createParseUser() instance +}); +``` + +### ParseUserQuery +##### (similar to ParseQuery class, but for ParseUser, not ParseObject) +##### https://docs.parseplatform.org/android/guide/#querying +```js +const parseUserQuery = Parse.createParseUserQuery({'className': 'parse-user-query'}); + +// execute same methods as ParseQuery class, but replace all ParseObject instances with ParseUser instances +``` + diff --git a/android/Resources/README.md b/android/Resources/README.md new file mode 100644 index 0000000..94a46bb --- /dev/null +++ b/android/Resources/README.md @@ -0,0 +1,5 @@ + +Files in this directory are copied to the APK's `assets/Resources` when doing an app build. +This is the same directory a Titanium app's `Resources` files are copied to. The app's +`Resources` files take priority and will be copied over module `Resources` files having +the same name. diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..5a3381f --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,9 @@ +repositories { + maven { url 'https://jitpack.io' } +} + + +dependencies { + implementation 'com.github.parse-community.Parse-SDK-Android:parse:2.0.3' + implementation 'com.github.parse-community:ParseLiveQuery-Android:1.2.2' +} diff --git a/android/dist/ti.parselivequery-android-1.1.0.zip b/android/dist/ti.parselivequery-android-1.1.0.zip new file mode 100644 index 0000000..0b4be54 Binary files /dev/null and b/android/dist/ti.parselivequery-android-1.1.0.zip differ diff --git a/android/lib/README b/android/lib/README new file mode 100644 index 0000000..6ada823 --- /dev/null +++ b/android/lib/README @@ -0,0 +1,6 @@ + +You can place your `*.jar` and `*.aar` library dependencies in this directory. + +Note that its best to reference dependencies in the module's "build.gradle" file +instead if you can. This avoids class name collision in case another module uses +the same library. diff --git a/android/manifest b/android/manifest new file mode 100644 index 0000000..49c6e0f --- /dev/null +++ b/android/manifest @@ -0,0 +1,18 @@ +# +# this is your module manifest and used by Titanium +# during compilation, packaging, distribution, etc. +# +version: 1.1.0 +apiversion: 4 +architectures: arm64-v8a armeabi-v7a x86 x86_64 +description: ti-parselivequery +author: Prashant Saini +license: Open Source +copyright: Copyright (c) 2022 by Prashant Saini + +# these should not be edited +name: ti-parselivequery +moduleid: ti.parselivequery +guid: f542beda-b74a-4af5-9479-4b2191e471eb +platform: android +minsdk: 9.0.0.GA diff --git a/android/platform/README.md b/android/platform/README.md new file mode 100644 index 0000000..99395a3 --- /dev/null +++ b/android/platform/README.md @@ -0,0 +1,27 @@ + +The `./build/android` directory is treated like a gradle project's `./src/main` directory. +These files will be bundled into the module's built AAR library and copied into the built app's APK. + +Adding files to the below folder will add them to APK's root "assets" folder. +(Note that a Titanium app's files under the `Resources` directory are copied to the APK's `assets/Resources`.) + + /build/android/assets + +The below folders are an example on how to add resource files to the APK's "res" folder. + + /build/android/res/drawable + /build/android/res/raw + /build/android/res/xml + +Prebuilt C/C++ `*.so` libraries must go under the following folder to be bundled with the AAR and APK. + + /build/android/jniLibs + +Android AIDL code generation files go under the following folder. The build system will automatically +generate Java code for them when the app that is built. + + /build/android/aidl + +Android "RenderScript" files (aka: `*.rs` files) go under the below folder. + + /build/android/rs diff --git a/android/src/ti/parselivequery/Constant.java b/android/src/ti/parselivequery/Constant.java new file mode 100644 index 0000000..13004cc --- /dev/null +++ b/android/src/ti/parselivequery/Constant.java @@ -0,0 +1,64 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +public class Constant { + // events related to `ParseLiveQueryClient` + final static String EVENT_CLIENT_CONNECTED = "clientConnected"; + final static String EVENT_CLIENT_DISCONNECTED = "clientDisconnected"; + final static String EVENT_CLIENT_SOCKET_ERROR = "clientSocketError"; + final static String EVENT_CLIENT_ERROR = "clientError"; + + + // events related to `createQuery` + final static String EVENT_QUERY_ERROR = "error"; + final static String EVENT_QUERY_SUBSCRIBE = "subscribe"; + final static String EVENT_QUERY_UNSUBSCRIBE = "unsubscribe"; + final static String EVENT_QUERY_EVENT = "event"; + + + // properties related to module + final static String PROPERTY_APP_ID = "appId"; + final static String PROPERTY_CLIENT_KEY = "clientKey"; + final static String PROPERTY_SERVER = "server"; + final static String PROPERTY_ENABLE_LOCAL_STORE = "enableLocalStore"; + final static boolean PROPERTY_ENABLE_LOCAL_STORE_DEFAULT = false; + + // properties related to all events + final static String PROPERTY_CLASS_VALUE = "value"; + final static String PROPERTY_CLASS_MSG = "message"; + final static String PROPERTY_ERROR_CODE = "code"; + + + // properties related to `createQuery` + final static String PROPERTY_CLASS_NAME = "className"; + final static String PROPERTY_SUCCESS = "success"; + final static String PROPERTY_PARSE_OBJECT = "parseObject"; + final static String PROPERTY_COUNT = "count"; + final static String PROPERTY_PARSE_OBJECTS = "parseObjects"; + + + // event properties related to `createQuery` + final static String PROPERTY_EVENT_TYPE = "parseEventType"; + +/* -------- v1.1.0 ---------- */ + // properties related to `createParseFile` + final static String PROPERTY_FILE_NAME = "fileName"; + final static String PROPERTY_FILE_DATA = "fileData"; // type TiBlob in Java, Ti.Blob in JS + final static String PROPERTY_FILE_PROGRESS = "fileProgress"; + + + // properties related to `createParseGeoPoint` + final static String PROPERTY_LATITUDE = "latitude"; + final static String PROPERTY_LONGITUDE = "longitude"; + + + // properties related to `createParsePolygon` + final static String PROPERTY_PARSE_GEOPOINT_LIST = "parseGeoPointList"; + + // properties related to `createParseUser` + final static String PROPERTY_PARSE_USER = "parseUser"; + final static String PROPERTY_PARSE_USERS = "parseUsers"; +} diff --git a/android/src/ti/parselivequery/ParseClientProxy.java b/android/src/ti/parselivequery/ParseClientProxy.java new file mode 100644 index 0000000..263fd4e --- /dev/null +++ b/android/src/ti/parselivequery/ParseClientProxy.java @@ -0,0 +1,103 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import com.parse.livequery.LiveQueryException; +import com.parse.livequery.ParseLiveQueryClient; +import com.parse.livequery.ParseLiveQueryClientCallbacks; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollProxy; +import org.appcelerator.kroll.annotations.Kroll; + +import static ti.parselivequery.Constant.EVENT_CLIENT_CONNECTED; +import static ti.parselivequery.Constant.EVENT_CLIENT_DISCONNECTED; +import static ti.parselivequery.Constant.EVENT_CLIENT_ERROR; +import static ti.parselivequery.Constant.EVENT_CLIENT_SOCKET_ERROR; +import static ti.parselivequery.Constant.PROPERTY_CLASS_VALUE; + +@SuppressWarnings("unused") +@Kroll.proxy(creatableInModule = TiParselivequeryModule.class) +public class ParseClientProxy extends KrollProxy implements ParseLiveQueryClientCallbacks { + private boolean isConnected = false; + ParseLiveQueryClient parseLiveQueryClient; + + public ParseClientProxy() { + parseLiveQueryClient = ParseLiveQueryClient.Factory.getClient(); + registerListener(); + } + + @Override + public void release() { + super.release(); + destroyClient(); + } + + @Kroll.getProperty + public boolean getIsConnected() { + return isConnected; + } + + @Kroll.method + public void registerListener() { + parseLiveQueryClient.registerListener(this); + } + + @Kroll.method + public void unregisterListener() { + parseLiveQueryClient.unregisterListener(this); + } + + @Kroll.method + public void reconnectClient() { + parseLiveQueryClient.reconnect(); + } + + @Kroll.method + public void reconnectClientIfNeeded() { + parseLiveQueryClient.connectIfNeeded(); + } + + @Kroll.method + public void disconnectClient() { + parseLiveQueryClient.disconnect(); + } + + @Kroll.method + public void destroyClient() { + disconnectClient(); + unregisterListener(); + parseLiveQueryClient = null; + } + + private void fireClientEvent(String eventName, Object value) { + KrollDict result = new KrollDict(); + result.put(PROPERTY_CLASS_VALUE, value); + fireEvent(eventName, result); + } + + @Override + public void onLiveQueryClientConnected(ParseLiveQueryClient client) { + isConnected = true; + fireClientEvent(EVENT_CLIENT_CONNECTED, true); + } + + @Override + public void onLiveQueryClientDisconnected(ParseLiveQueryClient client, boolean userInitiated) { + isConnected = false; + fireClientEvent(EVENT_CLIENT_DISCONNECTED, false); + } + + @Override + public void onLiveQueryError(ParseLiveQueryClient client, LiveQueryException reason) { + fireClientEvent(EVENT_CLIENT_ERROR, reason.getLocalizedMessage()); + } + + @Override + public void onSocketError(ParseLiveQueryClient client, Throwable reason) { + isConnected = false; + fireClientEvent(EVENT_CLIENT_SOCKET_ERROR, reason.getLocalizedMessage()); + } +} diff --git a/android/src/ti/parselivequery/ParseDataTypeConverter.java b/android/src/ti/parselivequery/ParseDataTypeConverter.java new file mode 100644 index 0000000..01f8415 --- /dev/null +++ b/android/src/ti/parselivequery/ParseDataTypeConverter.java @@ -0,0 +1,52 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import org.appcelerator.titanium.util.TiConvert; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Created by Prashant Saini on 10/10/22. + */ +public class ParseDataTypeConverter { + static Object toParseDataTypeFrom(Object value) { + Object parseDataTypeValue = value; + + if (value instanceof ParseObjectProxy) { + parseDataTypeValue = ((ParseObjectProxy) value).parseObject; + } else if (value instanceof ParseUserProxy) { + parseDataTypeValue = ((ParseUserProxy) value).getMyParseUser(); + } else if (value instanceof ParseFileProxy) { + parseDataTypeValue = ((ParseFileProxy) value).getParseFile(); + } else if (value instanceof ParseGeoPointProxy) { + parseDataTypeValue = ((ParseGeoPointProxy) value).getParseGeoPoint(); + } else if (value instanceof ParsePolygonProxy) { + parseDataTypeValue = ((ParsePolygonProxy) value).getParsePolygon(); + } else if (value instanceof HashMap) { + //noinspection unchecked + parseDataTypeValue = TiConvert.toJSON((HashMap) value); + } else if (value instanceof Object[]) { + parseDataTypeValue = TiConvert.toJSONArray((Object[]) value); + } else if (value == null) { + parseDataTypeValue = JSONObject.NULL; + } + + return parseDataTypeValue; + } + + static List toParseDataTypeFromArray(Object values) { + List list = new ArrayList<>(); + + for (Object nextObject : (Object[]) values) { + list.add( toParseDataTypeFrom(nextObject) ); + } + + return list; + } +} diff --git a/android/src/ti/parselivequery/ParseFileProxy.java b/android/src/ti/parselivequery/ParseFileProxy.java new file mode 100644 index 0000000..7110aac --- /dev/null +++ b/android/src/ti/parselivequery/ParseFileProxy.java @@ -0,0 +1,211 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import com.parse.ParseFile; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollFunction; +import org.appcelerator.kroll.KrollProxy; +import org.appcelerator.kroll.annotations.Kroll; +import org.appcelerator.titanium.TiBlob; + +import static ti.parselivequery.Constant.PROPERTY_FILE_DATA; +import static ti.parselivequery.Constant.PROPERTY_FILE_NAME; +import static ti.parselivequery.Constant.PROPERTY_FILE_PROGRESS; +import static ti.parselivequery.Util.checkException; +import static ti.parselivequery.Util.checkExceptionForResult; + +@SuppressWarnings("unused") +@Kroll.proxy(creatableInModule = TiParselivequeryModule.class) +public class ParseFileProxy extends KrollProxy { + private String fileName = ""; + private TiBlob fileBlob = null; + private ParseFile parseFile = null; + + @Override + public void release() { + super.release(); + + if (fileBlob != null) { + fileBlob.release(); + fileBlob = null; + } + + if (parseFile != null) { + parseFile.cancel(); + parseFile = null; + } + } + + @Override + public void handleCreationDict(KrollDict dict) { + super.handleCreationDict(dict); + + if (dict.containsKeyAndNotNull(PROPERTY_FILE_NAME)) + fileName = "" + dict.get(PROPERTY_FILE_NAME); + + if (dict.containsKeyAndNotNull(PROPERTY_FILE_DATA)) + fileBlob = (TiBlob) dict.get(PROPERTY_FILE_DATA); + } + + @Kroll.getProperty + public String getFileName() { + return fileName; + } + + @Kroll.setProperty + public void setFileName(String value) { + fileName = value; + } + + @Kroll.getProperty + public TiBlob getFileData() { + return fileBlob; + } + + @Kroll.setProperty + public void setFileData(TiBlob value) { + fileBlob = value; + } + + public ParseFile getParseFile() { + return parseFile; + } + + // exclusively set ParseFile instance which can then further be used to fetch data or perform other queries + public void setParseFile(ParseFile parseFile) { + this.parseFile = parseFile; + this.fileName = parseFile.getName(); + } + + // invoke this method to create ParseFile object internally once the file-name & blob is available + @Kroll.method + public boolean invalidate() { + // check if all required fields are available to make a new instance of ParseFile + if (!fileName.isEmpty() && fileBlob != null && fileBlob.getBytes().length != 0) { + + // cancel any ongoing parseFile operation + if (parseFile != null && parseFile.isDirty()) { + parseFile.cancel(); + } + + parseFile = new ParseFile(fileName, fileBlob.getBytes()); + return true; + } + + return false; + } + + /** + * Cancels the operations for this {@code ParseFile} if they are still in the task queue. + * However, if a network request has already been started for an operation, the network request + * will not be canceled. + */ + @Kroll.method + public void cancel() { + if (parseFile != null) { + parseFile.cancel(); + } + } + + /** + * The filename. Before save is called, this is just the filename given by the user (if any). + * After save is called, that name gets prefixed with a unique identifier. + */ + @Kroll.method + public String getName() { + if (parseFile != null) { + return parseFile.getName(); + } + + return ""; + } + + /** + * This returns the url of the file. It's only available after you save or after you get the + * file from a ParseObject. + */ + @Kroll.method + public String getUrl() { + if (parseFile != null) { + return parseFile.getUrl(); + } + + return ""; + } + + /** Whether the file has available data. */ + @Kroll.method + public boolean isDataAvailable() { + if (parseFile != null) { + return parseFile.isDataAvailable(); + } + + return false; + } + + /** Whether the file still needs to be saved. */ + @Kroll.method + public boolean isDirty() { + if (parseFile != null) { + return parseFile.isDirty(); + } + + return false; + } + + /** + * Asynchronously gets the data from cache if available or fetches its content from the network. + * @param dataCallback is called when the get completes. + * @param progressCallback is called periodically with progress updates. + */ + @Kroll.method + public void getDataInBackground(KrollFunction dataCallback, @Kroll.argument(optional = true) KrollFunction progressCallback) { + if (parseFile != null) { + parseFile.getDataInBackground((data, exc) -> { + KrollDict result = new KrollDict(); + boolean isSuccess = checkException(exc, result); + + if (isSuccess) { + fileBlob = TiBlob.blobFromData(data); + } + + result.put(PROPERTY_FILE_DATA, isSuccess ? fileBlob : null); + dataCallback.callAsync(krollObject, result); + + }, percentDone -> { + if (progressCallback != null) { + KrollDict result = new KrollDict(); + result.put(PROPERTY_FILE_PROGRESS, percentDone); + progressCallback.callAsync(krollObject, result); + } + }); + } + } + + /** + * Saves the file to the Parse cloud in a background thread. `progressCallback` is guaranteed to + * be called with 100 before saveCallback is called. + * @param saveCallback gets called when the save completes. + * @param progressCallback is called periodically with progress updates. + * */ + @Kroll.method + public void saveDataInBackground(@Kroll.argument(optional = true) KrollFunction saveCallback, @Kroll.argument(optional = true) KrollFunction progressCallback) { + if (parseFile != null) { + parseFile.saveInBackground(exc -> { + if (saveCallback != null) { + saveCallback.callAsync(krollObject, checkExceptionForResult(exc)); + } + }, percentDone -> { + if (progressCallback != null) { + KrollDict result = new KrollDict(); + result.put(PROPERTY_FILE_PROGRESS, percentDone); + progressCallback.callAsync(krollObject, result); + } + }); + } + } +} diff --git a/android/src/ti/parselivequery/ParseGeoPointProxy.java b/android/src/ti/parselivequery/ParseGeoPointProxy.java new file mode 100644 index 0000000..f50c845 --- /dev/null +++ b/android/src/ti/parselivequery/ParseGeoPointProxy.java @@ -0,0 +1,84 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import com.parse.ParseGeoPoint; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollProxy; +import org.appcelerator.kroll.annotations.Kroll; + +import static ti.parselivequery.Constant.PROPERTY_LATITUDE; +import static ti.parselivequery.Constant.PROPERTY_LONGITUDE; + +@SuppressWarnings("unused") +@Kroll.proxy(creatableInModule = TiParselivequeryModule.class) +public class ParseGeoPointProxy extends KrollProxy { + private double latitude = 90; + private double longitude = 180; + private ParseGeoPoint parseGeoPoint; + + @Override + public void release() { + super.release(); + } + + @Override + public void handleCreationDict(KrollDict dict) { + super.handleCreationDict(dict); + + if (dict.containsKeyAndNotNull(PROPERTY_LATITUDE) && dict.containsKeyAndNotNull(PROPERTY_LONGITUDE)) { + createParseGeoPoint(dict.getDouble(PROPERTY_LATITUDE), dict.getDouble(PROPERTY_LONGITUDE)); + } + } + + @Kroll.getProperty + public double getLatitude() { + return latitude; + } + + @Kroll.setProperty + public void setLatitude(double value) { + if (value < 90 && value > -90) { + latitude = value; + generateParseGeoPoint(); + } + } + + @Kroll.getProperty + public double getLongitude() { + return longitude; + } + + @Kroll.setProperty + public void setLongitude(double value) { + if (value < 180 && value > -180) { + longitude = value; + generateParseGeoPoint(); + } + } + + void setParseGeoPoint(ParseGeoPoint pgp) { + parseGeoPoint = pgp; + } + + ParseGeoPoint getParseGeoPoint() { + return parseGeoPoint; + } + + void createParseGeoPoint(double lt, double lng) { + if (lt < 90 && lt > -90 && lng < 180 && lng > -180) { + latitude = lt; + longitude = lng; + generateParseGeoPoint(); + } + } + + private void generateParseGeoPoint() { + if (latitude < 90 && latitude > -90 && longitude < 180 && longitude > -180) { + parseGeoPoint = new ParseGeoPoint(latitude, longitude); + } + } +} diff --git a/android/src/ti/parselivequery/ParseObjectProxy.java b/android/src/ti/parselivequery/ParseObjectProxy.java new file mode 100644 index 0000000..33640f9 --- /dev/null +++ b/android/src/ti/parselivequery/ParseObjectProxy.java @@ -0,0 +1,334 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import com.parse.ParseException; +import com.parse.ParseFile; +import com.parse.ParseGeoPoint; +import com.parse.ParseObject; +import com.parse.ParsePolygon; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollFunction; +import org.appcelerator.kroll.KrollProxy; +import org.appcelerator.kroll.annotations.Kroll; +import org.appcelerator.titanium.util.TiConvert; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import static ti.parselivequery.Constant.PROPERTY_CLASS_NAME; +import static ti.parselivequery.ParseDataTypeConverter.toParseDataTypeFrom; +import static ti.parselivequery.ParseDataTypeConverter.toParseDataTypeFromArray; +import static ti.parselivequery.Util.checkExceptionForResult; +import static ti.parselivequery.Util.toDate; + +@SuppressWarnings("unused") +@Kroll.proxy(creatableInModule = TiParselivequeryModule.class) +public class ParseObjectProxy extends KrollProxy { + ParseObject parseObject; + + public ParseObjectProxy(ParseObject parseObject) { + this.parseObject = parseObject; + } + + void onParseObjectResult(ParseException exc, KrollFunction callback) { + onParseObjectResult(exc, callback, null); + } + + void onParseObjectResult(ParseException exc, KrollFunction callback, ParseObject updatedParseObject) { + if (updatedParseObject != null) { + parseObject = updatedParseObject; + } + + if (callback != null) { + callback.callAsync(krollObject, checkExceptionForResult(exc)); + } + } + + @Override + public void handleCreationDict(KrollDict dict) { + super.handleCreationDict(dict); + + if (dict.containsKeyAndNotNull(PROPERTY_CLASS_NAME)) { + this.parseObject = new ParseObject(dict.getString(PROPERTY_CLASS_NAME)); + } + } + + @Override + public void release() { + super.release(); + parseObject = null; + } + + @Kroll.getProperty + public String getClassName() { + return parseObject.getClassName(); + } + + @Kroll.getProperty + public Date getUpdatedAt() { + return toDate(parseObject.getUpdatedAt()); + } + + @Kroll.getProperty + public boolean getIsAvailable() { + // to check whether the parseObject is ready for this instance + return parseObject != null; + } + + @Kroll.getProperty + public Date getCreatedAt() { + return toDate(parseObject.getCreatedAt()); + } + + @Kroll.getProperty + public String getObjectId() { + return parseObject.getObjectId(); + } + + @Kroll.setProperty + public void setObjectId(String key) { + parseObject.setObjectId(key); + } + + @Kroll.method + public void add(String key, Object object) { + if (object instanceof Object[]) { + parseObject.addAll(key, toParseDataTypeFromArray(object)); + } else { + parseObject.add(key, object); + } + } + + @Kroll.method + public void addUnique(String key, Object object) { + if (object instanceof Object[]) { + parseObject.addAllUnique(key, toParseDataTypeFromArray(object)); + } else { + parseObject.addUnique(key, object); + } + } + + @Kroll.method + public boolean containsKey(String key) { + return parseObject.containsKey(key); + } + + @Kroll.method + public void deleteEventually(@Kroll.argument(optional = true) KrollFunction callback) { + parseObject.deleteEventually(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void deleteInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseObject.deleteInBackground(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void fetchInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseObject.fetchInBackground((object, e) -> onParseObjectResult(e, callback, object)); + } + + @Kroll.method + public void fetchFromLocalDatastoreInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseObject.fetchFromLocalDatastoreInBackground((object, e) -> onParseObjectResult(e, callback, object)); + } + + @Kroll.method + public void fetchIfNeededInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseObject.fetchIfNeededInBackground((object, e) -> onParseObjectResult(e, callback, object)); + } + + @Kroll.method + public Object get(String key) { + return parseObject.get(key); + } + + @Kroll.method + public Object[] getJSONArray(String key) { + JSONArray jsonArray = parseObject.getJSONArray(key); + if (jsonArray == null) { + return null; + } + + return (Object[]) KrollDict.fromJSON(jsonArray); + } + + @Kroll.method + public Object getJSONObject(String key) { + JSONObject jsonObject = parseObject.getJSONObject(key); + if (jsonObject == null) { + return null; + } + + return KrollDict.fromJSON(jsonObject); + } + + @Kroll.method + public boolean has(String key) { + return parseObject.has(key); + } + + @Kroll.method + public boolean hasSameId(ParseObjectProxy parseObjectProxy) { + return parseObject.hasSameId(parseObjectProxy.parseObject); + } + + @Kroll.method + public void increment(String key, @Kroll.argument(optional = true) Object amount) { + if (amount == null) { + parseObject.increment(key); + } else { + parseObject.increment(key, (int) amount); + } + } + + @Kroll.method + public boolean isDataAvailable(@Kroll.argument(optional = true) Object key) { + if (key == null) { + return parseObject.isDataAvailable(); + } else { + return parseObject.isDataAvailable(key.toString()); + } + } + + @Kroll.method + public boolean isDirty(@Kroll.argument(optional = true) Object key) { + if (key == null) { + return parseObject.isDirty(); + } else { + return parseObject.isDirty(key.toString()); + } + } + + @Kroll.method + public String[] keySet() { + Set keySet = parseObject.keySet(); + return keySet == null ? null : TiConvert.toStringArray(keySet.toArray()); + } + + @Kroll.method + public void pinInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseObject.pinInBackground(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void pinInBackground(String key, @Kroll.argument(optional = true) KrollFunction callback) { + parseObject.pinInBackground(key, e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void put(String key, Object value) { + parseObject.put(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void remove(String key, @Kroll.argument(optional = true) Object values) { + if (values == null) { + parseObject.remove(key); + } else { + parseObject.removeAll(key, toParseDataTypeFromArray(values)); + } + } + + @Kroll.method + public void revert(@Kroll.argument(optional = true) String key) { + if (key == null) { + parseObject.revert(); + } else { + parseObject.revert(key); + } + } + + @Kroll.method + public void saveEventually(@Kroll.argument(optional = true) KrollFunction callback) { + parseObject.saveEventually(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void saveInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseObject.saveInBackground(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void unpinInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseObject.unpinInBackground(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void unpinInBackground(String key, @Kroll.argument(optional = true) KrollFunction callback) { + parseObject.unpinInBackground(key, e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public ParseFileProxy getParseFile(String key) { + ParseFile parseFile = parseObject.getParseFile(key); + + if (parseFile != null) { + ParseFileProxy parseFileProxy = new ParseFileProxy(); + parseFileProxy.setParseFile(parseFile); + return parseFileProxy; + } + + return null; + } + + @Kroll.method + public ParseGeoPointProxy getParseGeoPoint(String key) { + ParseGeoPoint parseGeoPoint = parseObject.getParseGeoPoint(key); + + if (parseGeoPoint != null) { + ParseGeoPointProxy parseGeoPointProxy = new ParseGeoPointProxy(); + parseGeoPointProxy.createParseGeoPoint(parseGeoPoint.getLatitude(), parseGeoPoint.getLongitude()); + return parseGeoPointProxy; + } + + return null; + } + + @Kroll.method + public ParsePolygonProxy getParsePolygon(String key) { + ParsePolygon parsePolygon = parseObject.getParsePolygon(key); + + if (parsePolygon != null) { + // get coordinates list from ParsePolygon + List parseGeoPoints = parsePolygon.getCoordinates(); + + // create ParseGeoPointProxy list from above coordinates + ArrayList parseGeoPointProxies = new ArrayList<>(); + for (ParseGeoPoint parseGeoPoint: parseGeoPoints) { + ParseGeoPointProxy parseGeoPointProxy = new ParseGeoPointProxy(); + parseGeoPointProxy.createParseGeoPoint(parseGeoPoint.getLatitude(), parseGeoPoint.getLongitude()); + + parseGeoPointProxies.add(parseGeoPointProxy); + } + + // create ParsePolygonProxy instance now + if (!parseGeoPointProxies.isEmpty()) { + ParsePolygonProxy parsePolygonProxy = new ParsePolygonProxy(); + parsePolygonProxy.setParseGeoPointList(parseGeoPointProxies.toArray()); + return parsePolygonProxy; + } + } + + return null; + } + + @Kroll.method + public ParseObjectProxy getParseObject(String key) { + ParseObject parseObjectPointer = parseObject.getParseObject(key); + + if (parseObjectPointer != null) { + return new ParseObjectProxy(parseObjectPointer); + } + + return null; + } +} diff --git a/android/src/ti/parselivequery/ParsePolygonProxy.java b/android/src/ti/parselivequery/ParsePolygonProxy.java new file mode 100644 index 0000000..1bba9a2 --- /dev/null +++ b/android/src/ti/parselivequery/ParsePolygonProxy.java @@ -0,0 +1,85 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import com.parse.ParseGeoPoint; +import com.parse.ParsePolygon; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollProxy; +import org.appcelerator.kroll.annotations.Kroll; + +import java.util.ArrayList; +import java.util.List; + +import static ti.parselivequery.Constant.PROPERTY_PARSE_GEOPOINT_LIST; +import static ti.parselivequery.Util.getParseGeoPoints; + +@SuppressWarnings("unused") +@Kroll.proxy(creatableInModule = TiParselivequeryModule.class) +public class ParsePolygonProxy extends KrollProxy { + private ArrayList parseGeoPointProxyList = new ArrayList<>(); + private ParsePolygon parsePolygon; + + ParsePolygon getParsePolygon() { + return parsePolygon; + } + + @Override + public void release() { + super.release(); + + if (parseGeoPointProxyList != null) { + parseGeoPointProxyList.clear(); + parseGeoPointProxyList = null; + } + + parsePolygon = null; + } + + @Override + public void handleCreationDict(KrollDict dict) { + super.handleCreationDict(dict); + + if (dict.containsKeyAndNotNull(PROPERTY_PARSE_GEOPOINT_LIST)) { + createParsePolygon(dict.get(PROPERTY_PARSE_GEOPOINT_LIST)); + } + } + + @Kroll.getProperty + public Object[] getParseGeoPointList() { + return parseGeoPointProxyList.toArray(); + } + + @Kroll.setProperty + public void setParseGeoPointList(Object list) { + createParsePolygon(list); + } + + @Kroll.method + public boolean containsPoint(Object parseGeoPointProxy) { + return parsePolygon.containsPoint(((ParseGeoPointProxy) parseGeoPointProxy).getParseGeoPoint()); + } + + void createParsePolygon(Object parseGeoPointProxies) { + // initiate ParseGeoPoint proxies + createParseGeoPointProxyList(parseGeoPointProxies); + + // create ParsePolygon instance now + List points = getParseGeoPoints(parseGeoPointProxies); + + if (!points.isEmpty()) { + parsePolygon = new ParsePolygon(points); + } + } + + void createParseGeoPointProxyList(Object parseGeoPointProxies) { + parseGeoPointProxyList.clear(); + + for (Object nextObject : (Object[]) parseGeoPointProxies) { + parseGeoPointProxyList.add((ParseGeoPointProxy) nextObject); + } + } +} diff --git a/android/src/ti/parselivequery/ParseUserProxy.java b/android/src/ti/parselivequery/ParseUserProxy.java new file mode 100644 index 0000000..11b148b --- /dev/null +++ b/android/src/ti/parselivequery/ParseUserProxy.java @@ -0,0 +1,380 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import com.parse.ParseException; +import com.parse.ParseFile; +import com.parse.ParseGeoPoint; +import com.parse.ParseObject; +import com.parse.ParsePolygon; +import com.parse.ParseUser; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollFunction; +import org.appcelerator.kroll.KrollProxy; +import org.appcelerator.kroll.annotations.Kroll; +import org.appcelerator.titanium.util.TiConvert; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import static ti.parselivequery.ParseDataTypeConverter.toParseDataTypeFrom; +import static ti.parselivequery.ParseDataTypeConverter.toParseDataTypeFromArray; +import static ti.parselivequery.Util.checkExceptionForResult; +import static ti.parselivequery.Util.toDate; + +@SuppressWarnings("unused") +@Kroll.proxy(creatableInModule = TiParselivequeryModule.class) +public class ParseUserProxy extends KrollProxy { + private ParseUser parseUser; + + public ParseUserProxy() { + this.parseUser = new ParseUser(); + } + + public ParseUserProxy(ParseUser parseUser1) { + this.parseUser = parseUser1; + } + + ParseUser getMyParseUser() { + return this.parseUser; + } + + void onParseObjectResult(ParseException exc, KrollFunction callback) { + onParseObjectResult(exc, callback, null); + } + + void onParseObjectResult(ParseException exc, KrollFunction callback, ParseObject updatedParseObject) { + if (callback != null) { + callback.callAsync(krollObject, checkExceptionForResult(exc)); + } + } + + private void fireCallback(ParseException exc, KrollFunction callback) { + if (callback != null) { + callback.callAsync(krollObject, checkExceptionForResult(exc)); + } + } + + @Override + public void release() { + super.release(); + parseUser = null; + } + + @Kroll.getProperty + public String getClassName() { + return parseUser.getClassName(); + } + + @Kroll.getProperty + public Date getUpdatedAt() { + return toDate(parseUser.getUpdatedAt()); + } + + @Kroll.getProperty + public boolean getIsAvailable() { + // to check whether the parseUser is ready for this instance + return parseUser != null; + } + + @Kroll.getProperty + public Date getCreatedAt() { + return toDate(parseUser.getCreatedAt()); + } + + @Kroll.getProperty + public String getObjectId() { + return parseUser.getObjectId(); + } + + @Kroll.setProperty + public void setObjectId(String key) { + parseUser.setObjectId(key); + } + + @Kroll.method + public void add(String key, Object object) { + if (object instanceof Object[]) { + parseUser.addAll(key, toParseDataTypeFromArray(object)); + } else { + parseUser.add(key, object); + } + } + + @Kroll.method + public void addUnique(String key, Object object) { + if (object instanceof Object[]) { + parseUser.addAllUnique(key, toParseDataTypeFromArray(object)); + } else { + parseUser.addUnique(key, object); + } + } + + @Kroll.method + public boolean containsKey(String key) { + return parseUser.containsKey(key); + } + + @Kroll.method + public void deleteEventually(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.deleteEventually(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void deleteInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.deleteInBackground(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void fetchInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.fetchInBackground((object, e) -> onParseObjectResult(e, callback, object)); + } + + @Kroll.method + public void fetchFromLocalDatastoreInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.fetchFromLocalDatastoreInBackground((object, e) -> onParseObjectResult(e, callback, object)); + } + + @Kroll.method + public void fetchIfNeededInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.fetchIfNeededInBackground((object, e) -> onParseObjectResult(e, callback, object)); + } + + @Kroll.method + public Object get(String key) { + return parseUser.get(key); + } + + @Kroll.method + public Object[] getJSONArray(String key) { + JSONArray jsonArray = parseUser.getJSONArray(key); + if (jsonArray == null) { + return null; + } + + return (Object[]) KrollDict.fromJSON(jsonArray); + } + + @Kroll.method + public Object getJSONObject(String key) { + JSONObject jsonObject = parseUser.getJSONObject(key); + if (jsonObject == null) { + return null; + } + + return KrollDict.fromJSON(jsonObject); + } + + @Kroll.method + public boolean has(String key) { + return parseUser.has(key); + } + + @Kroll.method + public boolean hasSameId(ParseObjectProxy parseObjectProxy) { + return parseUser.hasSameId(parseObjectProxy.parseObject); + } + + @Kroll.method + public void increment(String key, @Kroll.argument(optional = true) Object amount) { + if (amount == null) { + parseUser.increment(key); + } else { + parseUser.increment(key, (int) amount); + } + } + + @Kroll.method + public boolean isDataAvailable(@Kroll.argument(optional = true) Object key) { + if (key == null) { + return parseUser.isDataAvailable(); + } else { + return parseUser.isDataAvailable(key.toString()); + } + } + + @Kroll.method + public boolean isDirty(@Kroll.argument(optional = true) Object key) { + if (key == null) { + return parseUser.isDirty(); + } else { + return parseUser.isDirty(key.toString()); + } + } + + @Kroll.method + public String[] keySet() { + Set keySet = parseUser.keySet(); + return keySet == null ? null : TiConvert.toStringArray(keySet.toArray()); + } + + @Kroll.method + public void pinInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.pinInBackground(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void pinInBackground(String key, @Kroll.argument(optional = true) KrollFunction callback) { + parseUser.pinInBackground(key, e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void put(String key, Object value) { + parseUser.put(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void remove(String key, @Kroll.argument(optional = true) Object values) { + if (values == null) { + parseUser.remove(key); + } else { + parseUser.removeAll(key, toParseDataTypeFromArray(values)); + } + } + + @Kroll.method + public void revert(@Kroll.argument(optional = true) String key) { + if (key == null) { + parseUser.revert(); + } else { + parseUser.revert(key); + } + } + + @Kroll.method + public void saveEventually(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.saveEventually(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void saveInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.saveInBackground(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void unpinInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.unpinInBackground(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void unpinInBackground(String key, @Kroll.argument(optional = true) KrollFunction callback) { + parseUser.unpinInBackground(key, e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public ParseFileProxy getParseFile(String key) { + ParseFile parseFile = parseUser.getParseFile(key); + + if (parseFile != null) { + ParseFileProxy parseFileProxy = new ParseFileProxy(); + parseFileProxy.setParseFile(parseFile); + return parseFileProxy; + } + + return null; + } + + @Kroll.method + public ParseGeoPointProxy getParseGeoPoint(String key) { + ParseGeoPoint parseGeoPoint = parseUser.getParseGeoPoint(key); + + if (parseGeoPoint != null) { + ParseGeoPointProxy parseGeoPointProxy = new ParseGeoPointProxy(); + parseGeoPointProxy.createParseGeoPoint(parseGeoPoint.getLatitude(), parseGeoPoint.getLongitude()); + return parseGeoPointProxy; + } + + return null; + } + + @Kroll.method + public ParsePolygonProxy getParsePolygon(String key) { + ParsePolygon parsePolygon = parseUser.getParsePolygon(key); + + if (parsePolygon != null) { + // get coordinates list from ParsePolygon + List parseGeoPoints = parsePolygon.getCoordinates(); + + // create ParseGeoPointProxy list from above coordinates + ArrayList parseGeoPointProxies = new ArrayList<>(); + for (ParseGeoPoint parseGeoPoint : parseGeoPoints) { + ParseGeoPointProxy parseGeoPointProxy = new ParseGeoPointProxy(); + parseGeoPointProxy.createParseGeoPoint(parseGeoPoint.getLatitude(), parseGeoPoint.getLongitude()); + + parseGeoPointProxies.add(parseGeoPointProxy); + } + + // create ParsePolygonProxy instance now + if (!parseGeoPointProxies.isEmpty()) { + ParsePolygonProxy parsePolygonProxy = new ParsePolygonProxy(); + parsePolygonProxy.setParseGeoPointList(parseGeoPointProxies.toArray()); + return parsePolygonProxy; + } + } + + return null; + } + + @Kroll.method + public ParseUserProxy getParseUser(String key) { + ParseUser parseUserPointer = parseUser.getParseUser(key); + + if (parseUserPointer != null) { + return new ParseUserProxy(parseUserPointer); + } + + return null; + } + + @Kroll.method + public void setUsername(String value) { + parseUser.setUsername(value); + } + + @Kroll.method + public void setEmail(String value) { + parseUser.setEmail(value); + } + + @Kroll.method + public void setPassword(String value) { + parseUser.setPassword(value); + } + + @Kroll.method + public String getUsername() { + return parseUser.getUsername(); + } + + @Kroll.method + public String getEmail() { + return parseUser.getEmail(); + } + + @Kroll.method + public String getSessionToken() { + return parseUser.getSessionToken(); + } + + @Kroll.method + public boolean isNew() { + return parseUser.isNew(); + } + + @Kroll.method + public boolean isAuthenticated() { + return parseUser.isAuthenticated(); + } + + @Kroll.method + public void signUpInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUser.signUpInBackground(exc -> fireCallback(exc, callback)); + } +} diff --git a/android/src/ti/parselivequery/ParseUserQueryProxy.java b/android/src/ti/parselivequery/ParseUserQueryProxy.java new file mode 100644 index 0000000..dc72a0a --- /dev/null +++ b/android/src/ti/parselivequery/ParseUserQueryProxy.java @@ -0,0 +1,462 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import com.parse.ParseException; +import com.parse.ParseQuery; +import com.parse.ParseUser; +import com.parse.livequery.SubscriptionHandling; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollFunction; +import org.appcelerator.kroll.KrollProxy; +import org.appcelerator.kroll.annotations.Kroll; + +import java.util.List; + +import static ti.parselivequery.Constant.EVENT_QUERY_ERROR; +import static ti.parselivequery.Constant.EVENT_QUERY_EVENT; +import static ti.parselivequery.Constant.EVENT_QUERY_SUBSCRIBE; +import static ti.parselivequery.Constant.EVENT_QUERY_UNSUBSCRIBE; +import static ti.parselivequery.Constant.PROPERTY_CLASS_MSG; +import static ti.parselivequery.Constant.PROPERTY_CLASS_NAME; +import static ti.parselivequery.Constant.PROPERTY_COUNT; +import static ti.parselivequery.Constant.PROPERTY_EVENT_TYPE; +import static ti.parselivequery.Constant.PROPERTY_PARSE_USER; +import static ti.parselivequery.Constant.PROPERTY_PARSE_USERS; +import static ti.parselivequery.ParseDataTypeConverter.toParseDataTypeFrom; +import static ti.parselivequery.ParseDataTypeConverter.toParseDataTypeFromArray; +import static ti.parselivequery.Util.checkException; +import static ti.parselivequery.Util.createParseUserProxyList; +import static ti.parselivequery.Util.getParseGeoPoint; +import static ti.parselivequery.Util.getParseGeoPoints; +import static ti.parselivequery.Util.log; +import static ti.parselivequery.Util.toStringCollection; + + +@SuppressWarnings("unused") +@Kroll.proxy(creatableInModule = TiParselivequeryModule.class) +public class ParseUserQueryProxy extends KrollProxy { + private SubscriptionHandling subscriptionHandling; + private ParseQuery parseUserQuery; + + @Override + public void handleCreationDict(KrollDict dict) { + super.handleCreationDict(dict); + + if (dict.containsKeyAndNotNull(PROPERTY_CLASS_NAME)) { + parseUserQuery = ParseQuery.getQuery(dict.getString(PROPERTY_CLASS_NAME)); + } + } + + public ParseUserQueryProxy setParseUserQuery(ParseQuery parseUserQuery) { + this.parseUserQuery = parseUserQuery; + return this; + } + + void sendParseUser(KrollFunction callback, ParseException exc, ParseUser userObject) { + if (callback != null) { + KrollDict result = new KrollDict(); + boolean isSuccess = checkException(exc, result); + result.put(PROPERTY_PARSE_USER, isSuccess ? new ParseUserProxy(userObject) : null); + callback.callAsync(krollObject, result); + } + } + + void sendParseUsers(KrollFunction callback, ParseException exc, List objects) { + if (callback != null) { + KrollDict result = new KrollDict(); + checkException(exc, result); + result.put(PROPERTY_PARSE_USERS, createParseUserProxyList(objects).toArray()); + callback.callAsync(krollObject, result); + } + } + + void sendParseUserCount(KrollFunction callback, int count, ParseException exc) { + if (callback != null) { + KrollDict result = new KrollDict(); + boolean isSuccess = checkException(exc, result); + result.put(PROPERTY_COUNT, isSuccess ? count : -1); + callback.callAsync(krollObject, result); + } + } + + ParseQuery getParseQuery() { + return parseUserQuery; + } + + private void handleEvents() { + subscriptionHandling.handleSubscribe(query -> { + log("Query: `" + query.getClassName() + "` subscribed"); + KrollDict d = new KrollDict(); + d.put(PROPERTY_CLASS_MSG, ""); + fireEvent(EVENT_QUERY_SUBSCRIBE, d); + }); + + subscriptionHandling.handleUnsubscribe(query -> { + log("Query: `" + query.getClassName() + "` unsubscribed"); + subscriptionHandling = null; + KrollDict d = new KrollDict(); + d.put(PROPERTY_CLASS_MSG, ""); + fireEvent(EVENT_QUERY_UNSUBSCRIBE, d); + }); + + subscriptionHandling.handleError((query, exception) -> { + log("Query: `" + query.getClassName() + "` error: " + exception.getLocalizedMessage()); + KrollDict d = new KrollDict(); + d.put(PROPERTY_CLASS_MSG, exception.getLocalizedMessage()); + fireEvent(EVENT_QUERY_ERROR, d); + }); + + subscriptionHandling.handleEvents((query, event, userObject) -> { + log("Query: `" + query.getClassName() + "` event = " + event.name()); + KrollDict d = new KrollDict(); + String eventType = ""; + + switch (event) { + case CREATE: + eventType = TiParselivequeryModule.EVENT_TYPE_CREATED; + break; + case ENTER: + eventType = TiParselivequeryModule.EVENT_TYPE_ENTERED; + break; + case UPDATE: + eventType = TiParselivequeryModule.EVENT_TYPE_UPDATED; + break; + case LEAVE: + eventType = TiParselivequeryModule.EVENT_TYPE_LEFT; + break; + case DELETE: + eventType = TiParselivequeryModule.EVENT_TYPE_DELETED; + } + + d.put(PROPERTY_EVENT_TYPE, eventType); + + if (userObject != null) { + d.put(PROPERTY_PARSE_USER, new ParseUserProxy(userObject)); + } else { + d.put(PROPERTY_PARSE_USER, null); + } + + fireEvent(EVENT_QUERY_EVENT, d); + }); + } + + @Override + public void release() { + super.release(); + subscriptionHandling = null; + } + + @Kroll.method + public void subscribe(ParseClientProxy parseClientProxy) { + subscriptionHandling = parseClientProxy.parseLiveQueryClient.subscribe(parseUserQuery); + handleEvents(); + } + + @Kroll.method + public void unsubscribe(ParseClientProxy parseClientProxy) { + if (subscriptionHandling != null) { + parseClientProxy.parseLiveQueryClient.unsubscribe(parseUserQuery, subscriptionHandling); + } else { + parseClientProxy.parseLiveQueryClient.unsubscribe(parseUserQuery); + } + } + + @Kroll.method + public void findInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUserQuery.findInBackground((objects, exc) -> sendParseUsers(callback, exc, objects)); + } + + @Kroll.getProperty + public String getClassName() { + return parseUserQuery.getClassName(); + } + + @Kroll.getProperty + public boolean getIsRunning() { + return parseUserQuery.isRunning(); + } + + @Kroll.method + public void clear(String key) { + parseUserQuery.clear(key); + } + + @Kroll.method + public void addAscendingOrder(String key) { + parseUserQuery.addAscendingOrder(key); + } + + @Kroll.method + public void cancel() { + parseUserQuery.cancel(); + } + + @Kroll.method + public void clearCachedResult() { + parseUserQuery.clearCachedResult(); + } + + @Kroll.method + public void countInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUserQuery.countInBackground((count, exc) -> sendParseUserCount(callback, count, exc)); + } + + @Kroll.method + public void addDescendingOrder(String key) { + parseUserQuery.addDescendingOrder(key); + } + + @Kroll.method + public void fromLocalDatastore() { + parseUserQuery.fromLocalDatastore(); + } + + @Kroll.method + public void fromNetwork() { + parseUserQuery.fromNetwork(); + } + + @Kroll.method + public void fromPin(@Kroll.argument(optional = true) String key) { + if (key == null) { + parseUserQuery.fromPin(); + } else { + parseUserQuery.fromPin(key); + } + } + + @Kroll.method + public String getCachePolicy() { + // IGNORE_CACHE, CACHE_ONLY, NETWORK_ONLY, CACHE_ELSE_NETWORK, NETWORK_ELSE_CACHE, CACHE_THEN_NETWORK + return parseUserQuery.getCachePolicy().name(); + } + + @Kroll.method + public void getFirstInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseUserQuery.getFirstInBackground((userObject, exc) -> sendParseUser(callback, exc, userObject)); + } + + @Kroll.method + public void getInBackground(String key, @Kroll.argument(optional = true) KrollFunction callback) { + parseUserQuery.getInBackground(key, (userObject, exc) -> sendParseUser(callback, exc, userObject)); + } + + @Kroll.method + public int getLimit() { + return parseUserQuery.getLimit(); + } + + @Kroll.method + public int getMaxCacheAge() { + return (int) parseUserQuery.getMaxCacheAge(); + } + + @Kroll.method + public int getSkip() { + return parseUserQuery.getSkip(); + } + + @Kroll.method + public boolean hasCachedResult() { + return parseUserQuery.hasCachedResult(); + } + + @Kroll.method + public void ignoreACLs() { + parseUserQuery.ignoreACLs(); + } + + @Kroll.method + public void include(String key) { + parseUserQuery.include(key); + } + + @Kroll.method + public void orderByAscending(String key) { + parseUserQuery.orderByAscending(key); + } + + @Kroll.method + public void orderByDescending(String key) { + parseUserQuery.orderByDescending(key); + } + + @Kroll.method + public void selectKeys(Object keys) { + parseUserQuery.selectKeys(toStringCollection(keys)); + } + + @Kroll.method + public void setCachePolicy(String key) { + parseUserQuery.setCachePolicy(ParseQuery.CachePolicy.valueOf(key)); + } + + @Kroll.method + public void setLimit(int i) { + parseUserQuery.setLimit(i); + } + + @Kroll.method + public void setMaxCacheAge(int i) { + parseUserQuery.setMaxCacheAge(i); + } + + @Kroll.method + public void setSkip(int i) { + parseUserQuery.setSkip(i); + } + + @Kroll.method + public void setTrace(boolean enable) { + parseUserQuery.setTrace(enable); + } + + @Kroll.method + public void whereContainedIn(String key, Object values) { + parseUserQuery.whereContainedIn(key, toParseDataTypeFromArray(values)); + } + + @Kroll.method + public void whereContains(String key, String subKey) { + parseUserQuery.whereContains(key, subKey); + } + + @Kroll.method + public void whereContainsAll(String key, Object values) { + parseUserQuery.whereContainsAll(key, toParseDataTypeFromArray(values)); + } + + @Kroll.method + public void whereContainsAllStartsWith(String key, Object values) { + parseUserQuery.whereContainsAllStartsWith(key, toStringCollection(values)); + } + + @Kroll.method + public void whereDoesNotExist(String key) { + parseUserQuery.whereDoesNotExist(key); + } + + @Kroll.method + public void whereDoesNotMatchKeyInQuery(String key, String keyInQuery, ParseUserQueryProxy parseUserQueryProxy) { + parseUserQuery.whereDoesNotMatchKeyInQuery(key, keyInQuery, parseUserQueryProxy.parseUserQuery); + } + + @Kroll.method + public void whereDoesNotMatchQuery(String key, ParseUserQueryProxy parseUserQueryProxy) { + parseUserQuery.whereDoesNotMatchQuery(key, parseUserQueryProxy.parseUserQuery); + } + + @Kroll.method + public void whereEndsWith(String key, String value) { + parseUserQuery.whereEndsWith(key, value); + } + + @Kroll.method + public void whereEqualTo(String key, Object value) { + parseUserQuery.whereEqualTo(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereExists(String key) { + parseUserQuery.whereExists(key); + } + + @Kroll.method + public void whereFullText(String key, String value) { + parseUserQuery.whereFullText(key, value); + } + + @Kroll.method + public void whereGreaterThan(String key, Object value) { + parseUserQuery.whereGreaterThan(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereGreaterThanOrEqualTo(String key, Object value) { + parseUserQuery.whereGreaterThanOrEqualTo(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereLessThan(String key, Object value) { + parseUserQuery.whereLessThan(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereLessThanOrEqualTo(String key, Object value) { + parseUserQuery.whereLessThanOrEqualTo(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereMatches(String key, String value) { + parseUserQuery.whereMatches(key, value); + } + + @Kroll.method + public void whereMatchesKeyInQuery(String key, String keyInQuery, ParseUserQueryProxy parseUserQueryProxy) { + parseUserQuery.whereMatchesKeyInQuery(key, keyInQuery, parseUserQueryProxy.parseUserQuery); + } + + @Kroll.method + public void whereMatchesQuery(String key, ParseUserQueryProxy parseUserQueryProxy) { + parseUserQuery.whereMatchesQuery(key, parseUserQueryProxy.parseUserQuery); + } + + @Kroll.method + public void whereNotContainedIn(String key, Object values) { + parseUserQuery.whereNotContainedIn(key, toParseDataTypeFromArray(values)); + } + + @Kroll.method + public void whereNotEqualTo(String key, Object value) { + parseUserQuery.whereNotEqualTo(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereStartsWith(String key, String value) { + parseUserQuery.whereStartsWith(key, value); + } + + @Kroll.method + public void whereNear(String key, Object value) { + parseUserQuery.whereNear(key, getParseGeoPoint(value)); + } + + @Kroll.method + public void whereWithinKilometers(String key, Object value, double distance) { + parseUserQuery.whereWithinKilometers(key, getParseGeoPoint(value), distance); + } + + @Kroll.method + public void whereWithinMiles(String key, Object value, double distance) { + parseUserQuery.whereWithinMiles(key, getParseGeoPoint(value), distance); + } + + @Kroll.method + public void whereWithinRadians(String key, Object value, double distance) { + parseUserQuery.whereWithinRadians(key, getParseGeoPoint(value), distance); + } + + @Kroll.method + public void whereWithinGeoBox(String key, Object value1, Object value2) { + parseUserQuery.whereWithinGeoBox(key, getParseGeoPoint(value1), getParseGeoPoint(value2)); + } + + @Kroll.method + public void whereWithinPolygon(String key, Object parseGeoPointProxies) { + parseUserQuery.whereWithinPolygon(key, getParseGeoPoints(parseGeoPointProxies)); + } + + @Kroll.method + public void whereWithinPolygon(String key, ParsePolygonProxy parsePolygonProxy) { + parseUserQuery.whereWithinPolygon(key, parsePolygonProxy.getParsePolygon()); + } + + @Kroll.method + public void wherePolygonContains(String key, ParseGeoPointProxy parseGeoPointProxy) { + parseUserQuery.wherePolygonContains(key, parseGeoPointProxy.getParseGeoPoint()); + } +} diff --git a/android/src/ti/parselivequery/QueryProxy.java b/android/src/ti/parselivequery/QueryProxy.java new file mode 100644 index 0000000..58384b8 --- /dev/null +++ b/android/src/ti/parselivequery/QueryProxy.java @@ -0,0 +1,466 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import com.parse.ParseException; +import com.parse.ParseObject; +import com.parse.ParseQuery; +import com.parse.livequery.SubscriptionHandling; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollFunction; +import org.appcelerator.kroll.KrollProxy; +import org.appcelerator.kroll.annotations.Kroll; + +import java.util.List; + +import static ti.parselivequery.Constant.EVENT_QUERY_ERROR; +import static ti.parselivequery.Constant.EVENT_QUERY_EVENT; +import static ti.parselivequery.Constant.EVENT_QUERY_SUBSCRIBE; +import static ti.parselivequery.Constant.EVENT_QUERY_UNSUBSCRIBE; +import static ti.parselivequery.Constant.PROPERTY_CLASS_MSG; +import static ti.parselivequery.Constant.PROPERTY_CLASS_NAME; +import static ti.parselivequery.Constant.PROPERTY_COUNT; +import static ti.parselivequery.Constant.PROPERTY_EVENT_TYPE; +import static ti.parselivequery.Constant.PROPERTY_PARSE_OBJECT; +import static ti.parselivequery.Constant.PROPERTY_PARSE_OBJECTS; +import static ti.parselivequery.ParseDataTypeConverter.toParseDataTypeFrom; +import static ti.parselivequery.ParseDataTypeConverter.toParseDataTypeFromArray; +import static ti.parselivequery.Util.checkException; +import static ti.parselivequery.Util.createParseObjectProxyList; +import static ti.parselivequery.Util.getParseGeoPoint; +import static ti.parselivequery.Util.getParseGeoPoints; +import static ti.parselivequery.Util.log; +import static ti.parselivequery.Util.toStringCollection; + + +@SuppressWarnings("unused") +@Kroll.proxy(creatableInModule = TiParselivequeryModule.class) +public class QueryProxy extends KrollProxy { + private SubscriptionHandling subscriptionHandling; + private ParseQuery parseQuery; + + public QueryProxy() { + super(); + } + + @Override + public void handleCreationDict(KrollDict dict) { + super.handleCreationDict(dict); + + if (dict.containsKeyAndNotNull(PROPERTY_CLASS_NAME)) { + parseQuery = ParseQuery.getQuery(dict.getString(PROPERTY_CLASS_NAME)); + } + } + + public QueryProxy setParseQuery(ParseQuery parseQuery) { + this.parseQuery = parseQuery; + return this; + } + + void sendParseObject(KrollFunction callback, ParseException exc, ParseObject object) { + if (callback != null) { + KrollDict result = new KrollDict(); + boolean isSuccess = checkException(exc, result); + result.put(PROPERTY_PARSE_OBJECT, isSuccess ? new ParseObjectProxy(object) : null); + callback.callAsync(krollObject, result); + } + } + + void sendParseObjects(KrollFunction callback, ParseException exc, List objects) { + if (callback != null) { + KrollDict result = new KrollDict(); + checkException(exc, result); + result.put(PROPERTY_PARSE_OBJECTS, createParseObjectProxyList(objects).toArray()); + callback.callAsync(krollObject, result); + } + } + + void sendParseObjectCount(KrollFunction callback, int count, ParseException exc) { + if (callback != null) { + KrollDict result = new KrollDict(); + boolean isSuccess = checkException(exc, result); + result.put(PROPERTY_COUNT, isSuccess ? count : -1); + callback.callAsync(krollObject, result); + } + } + + ParseQuery getParseQuery() { + return parseQuery; + } + + private void handleEvents() { + subscriptionHandling.handleSubscribe(query -> { + log("Query: `" + query.getClassName() + "` subscribed"); + KrollDict d = new KrollDict(); + d.put(PROPERTY_CLASS_MSG, ""); + fireEvent(EVENT_QUERY_SUBSCRIBE, d); + }); + + subscriptionHandling.handleUnsubscribe(query -> { + log("Query: `" + query.getClassName() + "` unsubscribed"); + subscriptionHandling = null; + KrollDict d = new KrollDict(); + d.put(PROPERTY_CLASS_MSG, ""); + fireEvent(EVENT_QUERY_UNSUBSCRIBE, d); + }); + + subscriptionHandling.handleError((query, exception) -> { + log("Query: `" + query.getClassName() + "` error: " + exception.getLocalizedMessage()); + KrollDict d = new KrollDict(); + d.put(PROPERTY_CLASS_MSG, exception.getLocalizedMessage()); + fireEvent(EVENT_QUERY_ERROR, d); + }); + + subscriptionHandling.handleEvents((query, event, object) -> { + log("Query: `" + query.getClassName() + "` event = " + event.name()); + KrollDict d = new KrollDict(); + String eventType = ""; + + switch (event) { + case CREATE: + eventType = TiParselivequeryModule.EVENT_TYPE_CREATED; + break; + case ENTER: + eventType = TiParselivequeryModule.EVENT_TYPE_ENTERED; + break; + case UPDATE: + eventType = TiParselivequeryModule.EVENT_TYPE_UPDATED; + break; + case LEAVE: + eventType = TiParselivequeryModule.EVENT_TYPE_LEFT; + break; + case DELETE: + eventType = TiParselivequeryModule.EVENT_TYPE_DELETED; + } + + d.put(PROPERTY_EVENT_TYPE, eventType); + + if (object != null) { + d.put(PROPERTY_PARSE_OBJECT, new ParseObjectProxy(object)); + } else { + d.put(PROPERTY_PARSE_OBJECT, null); + } + + fireEvent(EVENT_QUERY_EVENT, d); + }); + } + + @Override + public void release() { + super.release(); + subscriptionHandling = null; + } + + @Kroll.method + public void subscribe(ParseClientProxy parseClientProxy) { + subscriptionHandling = parseClientProxy.parseLiveQueryClient.subscribe(parseQuery); + handleEvents(); + } + + @Kroll.method + public void unsubscribe(ParseClientProxy parseClientProxy) { + if (subscriptionHandling != null) { + parseClientProxy.parseLiveQueryClient.unsubscribe(parseQuery, subscriptionHandling); + } else { + parseClientProxy.parseLiveQueryClient.unsubscribe(parseQuery); + } + } + + @Kroll.method + public void findInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseQuery.findInBackground((objects, exc) -> sendParseObjects(callback, exc, objects)); + } + + @Kroll.getProperty + public String getClassName() { + return parseQuery.getClassName(); + } + + @Kroll.getProperty + public boolean getIsRunning() { + return parseQuery.isRunning(); + } + + @Kroll.method + public void clear(String key) { + parseQuery.clear(key); + } + + @Kroll.method + public void addAscendingOrder(String key) { + parseQuery.addAscendingOrder(key); + } + + @Kroll.method + public void cancel() { + parseQuery.cancel(); + } + + @Kroll.method + public void clearCachedResult() { + parseQuery.clearCachedResult(); + } + + @Kroll.method + public void countInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseQuery.countInBackground((count, exc) -> sendParseObjectCount(callback, count, exc)); + } + + @Kroll.method + public void addDescendingOrder(String key) { + parseQuery.addDescendingOrder(key); + } + + @Kroll.method + public void fromLocalDatastore() { + parseQuery.fromLocalDatastore(); + } + + @Kroll.method + public void fromNetwork() { + parseQuery.fromNetwork(); + } + + @Kroll.method + public void fromPin(@Kroll.argument(optional = true) String key) { + if (key == null) { + parseQuery.fromPin(); + } else { + parseQuery.fromPin(key); + } + } + + @Kroll.method + public String getCachePolicy() { + // IGNORE_CACHE, CACHE_ONLY, NETWORK_ONLY, CACHE_ELSE_NETWORK, NETWORK_ELSE_CACHE, CACHE_THEN_NETWORK + return parseQuery.getCachePolicy().name(); + } + + @Kroll.method + public void getFirstInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + parseQuery.getFirstInBackground((object, exc) -> sendParseObject(callback, exc, object)); + } + + @Kroll.method + public void getInBackground(String key, @Kroll.argument(optional = true) KrollFunction callback) { + parseQuery.getInBackground(key, (object, exc) -> sendParseObject(callback, exc, object)); + } + + @Kroll.method + public int getLimit() { + return parseQuery.getLimit(); + } + + @Kroll.method + public int getMaxCacheAge() { + return (int) parseQuery.getMaxCacheAge(); + } + + @Kroll.method + public int getSkip() { + return parseQuery.getSkip(); + } + + @Kroll.method + public boolean hasCachedResult() { + return parseQuery.hasCachedResult(); + } + + @Kroll.method + public void ignoreACLs() { + parseQuery.ignoreACLs(); + } + + @Kroll.method + public void include(String key) { + parseQuery.include(key); + } + + @Kroll.method + public void orderByAscending(String key) { + parseQuery.orderByAscending(key); + } + + @Kroll.method + public void orderByDescending(String key) { + parseQuery.orderByDescending(key); + } + + @Kroll.method + public void selectKeys(Object keys) { + parseQuery.selectKeys(toStringCollection(keys)); + } + + @Kroll.method + public void setCachePolicy(String key) { + parseQuery.setCachePolicy(ParseQuery.CachePolicy.valueOf(key)); + } + + @Kroll.method + public void setLimit(int i) { + parseQuery.setLimit(i); + } + + @Kroll.method + public void setMaxCacheAge(int i) { + parseQuery.setMaxCacheAge(i); + } + + @Kroll.method + public void setSkip(int i) { + parseQuery.setSkip(i); + } + + @Kroll.method + public void setTrace(boolean enable) { + parseQuery.setTrace(enable); + } + + @Kroll.method + public void whereContainedIn(String key, Object values) { + parseQuery.whereContainedIn(key, toParseDataTypeFromArray(values)); + } + + @Kroll.method + public void whereContains(String key, String subKey) { + parseQuery.whereContains(key, subKey); + } + + @Kroll.method + public void whereContainsAll(String key, Object values) { + parseQuery.whereContainsAll(key, toParseDataTypeFromArray(values)); + } + + @Kroll.method + public void whereContainsAllStartsWith(String key, Object values) { + parseQuery.whereContainsAllStartsWith(key, toStringCollection(values)); + } + + @Kroll.method + public void whereDoesNotExist(String key) { + parseQuery.whereDoesNotExist(key); + } + + @Kroll.method + public void whereDoesNotMatchKeyInQuery(String key, String keyInQuery, QueryProxy queryProxy) { + parseQuery.whereDoesNotMatchKeyInQuery(key, keyInQuery, queryProxy.parseQuery); + } + + @Kroll.method + public void whereDoesNotMatchQuery(String key, QueryProxy queryProxy) { + parseQuery.whereDoesNotMatchQuery(key, queryProxy.parseQuery); + } + + @Kroll.method + public void whereEndsWith(String key, String value) { + parseQuery.whereEndsWith(key, value); + } + + @Kroll.method + public void whereEqualTo(String key, Object value) { + parseQuery.whereEqualTo(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereExists(String key) { + parseQuery.whereExists(key); + } + + @Kroll.method + public void whereFullText(String key, String value) { + parseQuery.whereFullText(key, value); + } + + @Kroll.method + public void whereGreaterThan(String key, Object value) { + parseQuery.whereGreaterThan(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereGreaterThanOrEqualTo(String key, Object value) { + parseQuery.whereGreaterThanOrEqualTo(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereLessThan(String key, Object value) { + parseQuery.whereLessThan(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereLessThanOrEqualTo(String key, Object value) { + parseQuery.whereLessThanOrEqualTo(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereMatches(String key, String value) { + parseQuery.whereMatches(key, value); + } + + @Kroll.method + public void whereMatchesKeyInQuery(String key, String keyInQuery, QueryProxy queryProxy) { + parseQuery.whereMatchesKeyInQuery(key, keyInQuery, queryProxy.parseQuery); + } + + @Kroll.method + public void whereMatchesQuery(String key, QueryProxy queryProxy) { + parseQuery.whereMatchesQuery(key, queryProxy.parseQuery); + } + + @Kroll.method + public void whereNotContainedIn(String key, Object values) { + parseQuery.whereNotContainedIn(key, toParseDataTypeFromArray(values)); + } + + @Kroll.method + public void whereNotEqualTo(String key, Object value) { + parseQuery.whereNotEqualTo(key, toParseDataTypeFrom(value)); + } + + @Kroll.method + public void whereStartsWith(String key, String value) { + parseQuery.whereStartsWith(key, value); + } + + @Kroll.method + public void whereNear(String key, Object value) { + parseQuery.whereNear(key, getParseGeoPoint(value)); + } + + @Kroll.method + public void whereWithinKilometers(String key, Object value, double distance) { + parseQuery.whereWithinKilometers(key, getParseGeoPoint(value), distance); + } + + @Kroll.method + public void whereWithinMiles(String key, Object value, double distance) { + parseQuery.whereWithinMiles(key, getParseGeoPoint(value), distance); + } + + @Kroll.method + public void whereWithinRadians(String key, Object value, double distance) { + parseQuery.whereWithinRadians(key, getParseGeoPoint(value), distance); + } + + @Kroll.method + public void whereWithinGeoBox(String key, Object value1, Object value2) { + parseQuery.whereWithinGeoBox(key, getParseGeoPoint(value1), getParseGeoPoint(value2)); + } + + @Kroll.method + public void whereWithinPolygon(String key, Object parseGeoPointProxies) { + parseQuery.whereWithinPolygon(key, getParseGeoPoints(parseGeoPointProxies)); + } + + @Kroll.method + public void whereWithinPolygon(String key, ParsePolygonProxy parsePolygonProxy) { + parseQuery.whereWithinPolygon(key, parsePolygonProxy.getParsePolygon()); + } + + @Kroll.method + public void wherePolygonContains(String key, ParseGeoPointProxy parseGeoPointProxy) { + parseQuery.wherePolygonContains(key, parseGeoPointProxy.getParseGeoPoint()); + } +} diff --git a/android/src/ti/parselivequery/TiParselivequeryModule.java b/android/src/ti/parselivequery/TiParselivequeryModule.java new file mode 100644 index 0000000..102156a --- /dev/null +++ b/android/src/ti/parselivequery/TiParselivequeryModule.java @@ -0,0 +1,194 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import com.parse.Parse; +import com.parse.ParseAnonymousUtils; +import com.parse.ParseException; +import com.parse.ParseObject; +import com.parse.ParseUser; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollFunction; +import org.appcelerator.kroll.KrollModule; +import org.appcelerator.kroll.annotations.Kroll; + +import static ti.parselivequery.Util.AppContext; +import static ti.parselivequery.Util.checkExceptionForResult; +import static ti.parselivequery.Util.createCompoundQueryOr; +import static ti.parselivequery.Util.fireCallbackForParseUser; +import static ti.parselivequery.Util.getParseObjectList; +import static ti.parselivequery.Util.log; + + +@SuppressWarnings({"unused", "SpellCheckingInspection"}) +@Kroll.module(name = "TiParselivequery", id = "ti.parselivequery") +public class TiParselivequeryModule extends KrollModule { + private Parse.Configuration parseConfig; + + @Kroll.constant + public final static int LOG_LEVEL_DEBUG = Parse.LOG_LEVEL_DEBUG; + @Kroll.constant + public final static int LOG_LEVEL_ERROR = Parse.LOG_LEVEL_ERROR; + @Kroll.constant + public final static int LOG_LEVEL_INFO = Parse.LOG_LEVEL_INFO; + @Kroll.constant + public final static int LOG_LEVEL_VERBOSE = Parse.LOG_LEVEL_VERBOSE; + @Kroll.constant + public final static int LOG_LEVEL_WARNING = Parse.LOG_LEVEL_WARNING; + @Kroll.constant + public final static int LOG_LEVEL_NONE = Parse.LOG_LEVEL_NONE; + + @Kroll.constant + public final static String IGNORE_CACHE = "IGNORE_CACHE"; // ParseQuery.CachePolicy.IGNORE_CACHE + @Kroll.constant + public final static String CACHE_ONLY = "CACHE_ONLY"; // ParseQuery.CachePolicy.CACHE_ONLY + @Kroll.constant + public final static String NETWORK_ONLY = "NETWORK_ONLY"; // ParseQuery.CachePolicy.NETWORK_ONLY + @Kroll.constant + public final static String CACHE_ELSE_NETWORK = "CACHE_ELSE_NETWORK"; // ParseQuery.CachePolicy.CACHE_ELSE_NETWORK + @Kroll.constant + public final static String NETWORK_ELSE_CACHE = "NETWORK_ELSE_CACHE"; // ParseQuery.CachePolicy.NETWORK_ELSE_CACHE + @Kroll.constant + public final static String CACHE_THEN_NETWORK = "CACHE_THEN_NETWORK"; // ParseQuery.CachePolicy.CACHE_THEN_NETWORK + + @Kroll.constant + public final static String EVENT_TYPE_ENTERED = "CREATE"; // Event.CREATE + @Kroll.constant + public final static String EVENT_TYPE_LEFT = "ENTER"; // Event.ENTER + @Kroll.constant + public final static String EVENT_TYPE_CREATED = "UPDATE"; // Event.UPDATE + @Kroll.constant + public final static String EVENT_TYPE_UPDATED = "LEAVE"; // Event.LEAVE + @Kroll.constant + public final static String EVENT_TYPE_DELETED = "DELETE"; // Event.DELETE + + private void onParseObjectResult(ParseException exc, KrollFunction callback) { + if (callback != null) { + callback.callAsync(krollObject, checkExceptionForResult(exc)); + } + } + + @Kroll.method + public boolean initialize(KrollDict options) { + if (parseConfig == null) { + Parse.Configuration.Builder parseBuilder = new Parse.Configuration.Builder(AppContext()); + parseBuilder.applicationId(options.getString(Constant.PROPERTY_APP_ID)); + parseBuilder.clientKey(options.getString(Constant.PROPERTY_CLIENT_KEY)); + parseBuilder.server(options.getString(Constant.PROPERTY_SERVER)); + + if (options.optBoolean(Constant.PROPERTY_ENABLE_LOCAL_STORE, Constant.PROPERTY_ENABLE_LOCAL_STORE_DEFAULT)) { + parseBuilder.enableLocalDataStore(); + } + + parseConfig = parseBuilder.build(); + log("Parse initialized"); + } else { + log("Parse is already initialized"); + } + + Parse.initialize(parseConfig); + return true; + } + + @Kroll.method + public void destroyParse() { + Parse.destroy(); + } + + @Kroll.method + public void setLogLevel(int logLevel) { + Parse.setLogLevel(logLevel); + } + + @Kroll.method + public void setServer(String url) { + Parse.setServer(url); + } + + @Kroll.method + public void fetchAllInBackground(Object values, @Kroll.argument(optional = true) KrollFunction callback) { + ParseObject.fetchAllInBackground(getParseObjectList(values), (objects, e) -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void pinAllInBackground(Object values, @Kroll.argument(optional = true) KrollFunction callback) { + ParseObject.pinAllInBackground(getParseObjectList(values), e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void pinAllInBackground(String key, Object values, @Kroll.argument(optional = true) KrollFunction callback) { + ParseObject.pinAllInBackground(key, getParseObjectList(values), e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void saveAllInBackground(Object values, @Kroll.argument(optional = true) KrollFunction callback) { + ParseObject.saveAllInBackground(getParseObjectList(values), e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void unpinAllInBackground(@Kroll.argument(optional = true) KrollFunction callback) { + ParseObject.unpinAllInBackground(e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void unpinAllInBackground(Object values, @Kroll.argument(optional = true) KrollFunction callback) { + ParseObject.unpinAllInBackground(getParseObjectList(values), e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void unpinAllInBackground(String key, @Kroll.argument(optional = true) KrollFunction callback) { + ParseObject.unpinAllInBackground(key, e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public void unpinAllInBackground(String key, Object values, @Kroll.argument(optional = true) KrollFunction callback) { + ParseObject.unpinAllInBackground(key, getParseObjectList(values), e -> onParseObjectResult(e, callback)); + } + + @Kroll.method + public QueryProxy createCompoundQuery(Object values) { + return createCompoundQueryOr(values); + } + + @Kroll.method + public ParseUserProxy getCurrentUser() { + return Util.parseUserProxy(ParseUser.getCurrentUser()); + } + + @Kroll.method + public void enableAutomaticUser() { + ParseUser.enableAutomaticUser(); + } + + @Kroll.method + public boolean isLinked(@Kroll.argument (optional = true) ParseUserProxy parseUserProxy) { + if (parseUserProxy == null) { + return ParseAnonymousUtils.isLinked(ParseUser.getCurrentUser()); + } else { + return ParseAnonymousUtils.isLinked(parseUserProxy.getMyParseUser()); + } + } + + @Kroll.method + public void loginInBackground(String username, String password, KrollFunction callback) { + ParseUser.logInInBackground(username, password, (user, exc) -> fireCallbackForParseUser(user, krollObject, exc, callback)); + } + + @Kroll.method + public void logOutInBackground(KrollFunction callback) { + ParseUser.logOutInBackground(exc -> fireCallbackForParseUser(null, krollObject, exc, callback)); + } + + @Kroll.method + public void anonymousLogIn(KrollFunction callback) { + ParseAnonymousUtils.logIn((user, exc) -> fireCallbackForParseUser(user, krollObject, exc, callback)); + } + + @Kroll.method + public void becomeInBackground(String sessionToken, KrollFunction callback) { + ParseUser.becomeInBackground(sessionToken, (user, exc) -> fireCallbackForParseUser(user, krollObject, exc, callback)); + } +} diff --git a/android/src/ti/parselivequery/Util.java b/android/src/ti/parselivequery/Util.java new file mode 100644 index 0000000..d94a9d7 --- /dev/null +++ b/android/src/ti/parselivequery/Util.java @@ -0,0 +1,171 @@ +/* + * Created by Prashant Saini + */ + +package ti.parselivequery; + +import android.content.Context; +import android.util.Log; + +import com.parse.ParseException; +import com.parse.ParseGeoPoint; +import com.parse.ParseObject; +import com.parse.ParseQuery; +import com.parse.ParseUser; + +import org.appcelerator.kroll.KrollDict; +import org.appcelerator.kroll.KrollFunction; +import org.appcelerator.kroll.KrollObject; +import org.appcelerator.titanium.TiApplication; +import org.appcelerator.titanium.util.TiConvert; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import static ti.parselivequery.Constant.PROPERTY_CLASS_MSG; +import static ti.parselivequery.Constant.PROPERTY_ERROR_CODE; +import static ti.parselivequery.Constant.PROPERTY_PARSE_USER; +import static ti.parselivequery.Constant.PROPERTY_SUCCESS; + + +public class Util { + final static String TAG = "TiParse"; + + static Context AppContext() { + return TiApplication.getInstance().getApplicationContext(); + } + + static void log(String msg) { + Log.i(TAG, msg); + } + + static List toStringCollection(Object jsArray) { + return Arrays.asList( TiConvert.toStringArray( (Object[]) jsArray) ); + } + + static boolean checkException(ParseException e, KrollDict result) { + boolean isSuccess = e == null; + result.put(PROPERTY_SUCCESS, isSuccess); + result.put(PROPERTY_ERROR_CODE, isSuccess ? null : e.getCode()); + result.put(PROPERTY_CLASS_MSG, isSuccess ? "" : e.getLocalizedMessage()); + return isSuccess; + } + + static KrollDict checkExceptionForResult(ParseException e) { + boolean isSuccess = e == null; + KrollDict result = new KrollDict(); + result.put(PROPERTY_SUCCESS, isSuccess); + result.put(PROPERTY_ERROR_CODE, isSuccess ? null : e.getCode()); + result.put(PROPERTY_CLASS_MSG, isSuccess ? "" : e.getLocalizedMessage()); + return result; + } + + static ArrayList createParseObjectProxyList(List objects) { + ArrayList parseObjectProxyList = new ArrayList<>(); + + if (objects != null && objects.size() > 0) { + for (ParseObject object : objects) { + parseObjectProxyList.add(new ParseObjectProxy(object)); + } + } + + return parseObjectProxyList; + } + + static ArrayList createParseUserProxyList(List userObjects) { + ArrayList parseUserProxyList = new ArrayList<>(); + + if (userObjects != null && userObjects.size() > 0) { + for (ParseUser userObject : userObjects) { + parseUserProxyList.add(new ParseUserProxy(userObject)); + } + } + + return parseUserProxyList; + } + + static List getParseObjectList(Object values) { + ArrayList parseObjectArrayList = new ArrayList<>(); + + if (values instanceof Object[]) { + for (Object value : (Object[]) values) { + if (value instanceof ParseObjectProxy) { + parseObjectArrayList.add(((ParseObjectProxy) value).parseObject); + } + } + } + + return parseObjectArrayList; + } + + static Date toDate(Date date) { + if (date == null) { + return null; + } + + return TiConvert.toDate(date); + } + + static ArrayList createQueryProxyList(Object values) { + ArrayList queryProxyList = new ArrayList<>(); + + if (values instanceof Object[]) { + for (Object value : (Object[]) values) { + if (value instanceof QueryProxy) { + queryProxyList.add(((QueryProxy) value)); + } + } + } + + return queryProxyList; + } + + static QueryProxy createCompoundQueryOr(Object values) { + ArrayList queryProxyList = createQueryProxyList(values); + + if (queryProxyList.size() > 0) { + List> queries = new ArrayList<>(); + + for (QueryProxy queryProxy : queryProxyList) { + queries.add(queryProxy.getParseQuery()); + } + + return new QueryProxy().setParseQuery( ParseQuery.or(queries) ); + + } else { + return null; + } + } + + static ParseGeoPoint getParseGeoPoint(Object value) { + return ((ParseGeoPointProxy) value).getParseGeoPoint(); + } + + static List getParseGeoPoints(Object list) { + // create ParsePolygon instance now + List parseGeoPoints = new ArrayList<>(); + + for (Object nextObject: (Object[]) list) { + parseGeoPoints.add( ((ParseGeoPointProxy) nextObject).getParseGeoPoint() ); + } + + return parseGeoPoints; + } + + static ParseUserProxy parseUserProxy(ParseUser parseUser) { + if (parseUser != null) { + return new ParseUserProxy(parseUser); + } else { + return null; + } + } + + static void fireCallbackForParseUser(ParseUser parseUser, KrollObject krollObject, ParseException exc, KrollFunction callback) { + KrollDict result = new KrollDict(); + boolean isSuccess = checkException(exc, result); + result.put(PROPERTY_PARSE_USER, isSuccess ? Util.parseUserProxy(parseUser) : null); + callback.callAsync(krollObject, result); + } +} diff --git a/android/timodule.xml b/android/timodule.xml new file mode 100644 index 0000000..ae31597 --- /dev/null +++ b/android/timodule.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/assets/README b/assets/README new file mode 100644 index 0000000..5ba6b2a --- /dev/null +++ b/assets/README @@ -0,0 +1,7 @@ +Place your assets like PNG files in this directory and they will be packaged +with your module. + +All JavaScript files in the assets directory are IGNORED except if you create a +file named "ti.parselivequery.js" in this directory in which case it will be +wrapped by native code, compiled, and used as your module. This allows you to +run pure JavaScript modules that are pre-compiled.