package com.aliao.android.hipster; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import com.parse.FindCallback; import com.parse.FunctionCallback; import com.parse.GetDataCallback; import com.parse.ParseCloud; import com.parse.ParseException; import com.parse.ParseFile; import com.parse.ParseObject; import com.parse.ParseQuery; import com.parse.ParseUser; import java.io.ByteArrayOutputStream; import java.util.HashMap; import java.util.List; import java.util.Random; /** * Implementation of Hipster actions using Facebook's Parse API. */ public class ParseHipsterActions implements HipsterActions { // Cloud API method names. private static final String CLOUD_GET_NEXT = "findHipster"; private static final String CLOUD_CONNECT = "connect"; // Connect method field names. private static final String CONNECT_FROM_USER = "userFrom"; private static final String CONNECT_TO_USER = "userTo"; // Reference to current user. Should only be read from the main UI thread. private HipsterUser currentUser; private ParseHipsterActions() { if (ParseUser.getCurrentUser() != null) { currentUser = createHipsterUser(ParseUser.getCurrentUser()); } } public static ParseHipsterActions newInstance() { return new ParseHipsterActions(); } @Override public HipsterUser getCurrentUser() { return currentUser; } @Override public void getUserScoreAsync(final HipsterUser user, final OnScoreCallback callback) { ParseQuery<ParseUser> userParseQuery = ParseUser.getQuery(); userParseQuery.whereEqualTo("objectId", user.getUserId()); userParseQuery.findInBackground(new FindCallback<ParseUser>() { public void done(List<ParseUser> objects, ParseException error) { if (error != null) { // Something went wrong. callback.onError(new HipsterException(error)); return; } if (objects == null || objects.isEmpty()) { callback.onError(new HipsterException("Can't find user " + user.getUserName())); return; } // The query was successful. ParseUser parseUser = objects.get(0); ParseQuery<ParseObject> query = ParseQuery.getQuery(Score.SCORE_CLASS); query.whereEqualTo(Score.USER_FIELD, parseUser); query.findInBackground(new FindCallback<ParseObject>() { @Override public void done(List<ParseObject> parseObjects, ParseException error) { if (error != null) { callback.onError(new HipsterException(error)); return; } if (parseObjects == null || parseObjects.size() == 0) { callback.onError(new HipsterException("Error fetching score.")); return; } callback.onSuccess(user, parseObjects.get(0).getInt(Score.SCORE_FIELD)); } }); } }); } @Override public void getUserPhotoAsync(final HipsterUser user, final OnPhotoCallback callback) { ParseQuery<ParseUser> userParseQuery = ParseUser.getQuery(); userParseQuery.whereEqualTo("objectId", user.getUserId()); userParseQuery.findInBackground(new FindCallback<ParseUser>() { public void done(List<ParseUser> objects, ParseException error) { if (error != null) { // Something went wrong. callback.onError(new HipsterException(error)); return; } if (objects == null || objects.size() == 0) { callback.onError(new HipsterException("Can't find user " + user.getUserName())); return; } // The query was successful. ParseUser parseUser = objects.get(0); ParseFile photoFile = parseUser.getParseFile(User.PHOTO_KEY); photoFile.getDataInBackground(new GetDataCallback() { @Override public void done(byte[] bytes, ParseException error) { if (error != null) { callback.onError(new HipsterException(error)); return; } Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); callback.onSuccess(user, bitmap); } }); } }); } @Override public void signUpAsync(final String userName, final Bitmap photo, final OnSignUpCallback callback) { AsyncTask<Void, Void, ParseUser> createUserTask = new AsyncTask<Void, Void, ParseUser>() { byte[] photoBytes; Exception exception; @Override protected void onPreExecute() { super.onPreExecute(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); photo.compress(Bitmap.CompressFormat.PNG, 100, stream); photoBytes = stream.toByteArray(); } @Override protected ParseUser doInBackground(Void... params) { // Upload user photo to a remote file. ParseFile photo = new ParseFile(User.PHOTO_FILE_NAME, photoBytes); try { photo.save(); } catch (ParseException error) { exception = error; return null; } // Sign up a Parse user with photo field links to the remote photo file ParseUser user = new ParseUser(); user.setUsername(userName.toLowerCase()); user.setPassword(userName.toLowerCase()); String verifyCode = generateCode(); user.put(User.VERIFY_CODE_KEY, verifyCode); user.put(User.PHOTO_KEY, photo); try { user.signUp(); } catch (ParseException error) { exception = error; return null; } // Add a row to score table links to the current Parse user ParseObject score = new ParseObject(Score.SCORE_CLASS); score.put(Score.USER_FIELD, user); score.put(Score.SCORE_FIELD, 0); try { score.save(); } catch (ParseException error) { exception = error; return null; } return user; } @Override protected void onPostExecute(ParseUser parseUser) { super.onPostExecute(parseUser); // Error happened during sign up if (exception != null) { exception.printStackTrace(); callback.onError(new HipsterException(exception)); return; } currentUser = createHipsterUser(parseUser); callback.onSuccess(currentUser); } }; createUserTask.execute(); } // Generate 3 digit code. private String generateCode() { Random random = new Random(); return String.valueOf(random.nextInt(10)) + String.valueOf(random.nextInt(10)) + String .valueOf(random.nextInt(10)); } @Override public void getRandomHipsterAsync(final OnNextUserFoundCallback callback) { HashMap<String, String> parameters = new HashMap<String, String>(); parameters.put("userId", currentUser.getUserId()); ParseCloud.callFunctionInBackground(CLOUD_GET_NEXT, parameters, new FunctionCallback<ParseUser>() { public void done(ParseUser parseUser, ParseException error) { if (error != null) { callback.onError(new HipsterException(error)); return; } HipsterUser hipsterUser = createHipsterUser(parseUser); callback.onSuccess(hipsterUser); } } ); } @Override public void connectUserAsync(final HipsterUser userFrom, final HipsterUser userTo, final OnConnectUserCallback callback) { HashMap<String, String> parameters = new HashMap<String, String>(); parameters.put(CONNECT_FROM_USER, userFrom.getUserId()); parameters.put(CONNECT_TO_USER, userTo.getUserId()); parameters.put(User.VERIFY_CODE_KEY, userTo.getVerificationCode()); ParseCloud.callFunctionInBackground(CLOUD_CONNECT, parameters, new FunctionCallback<String>() { public void done(String response, ParseException error) { if (error != null) { callback.onError(new HipsterException(error)); return; } callback.onSuccess(userFrom, userTo); } }); } HipsterUser createHipsterUser(ParseUser parseUser) { return new HipsterUser(parseUser.getObjectId(), parseUser.getUsername(), (String) parseUser.get(User.VERIFY_CODE_KEY)); } // user data fields static class User { static final String PHOTO_FILE_NAME = "user_photo"; static final String VERIFY_CODE_KEY = "verifyCode"; static final String PHOTO_KEY = "photo"; } // Score class map to Score table on Parse server static class Score { static final String SCORE_CLASS = "Score"; static final String USER_FIELD = "userId"; static final String SCORE_FIELD = "score"; } }