diff --git a/app/src/main/java/edu/sc/snacktrack/login/NewAccountFragment.java b/app/src/main/java/edu/sc/snacktrack/login/NewAccountFragment.java
index 2d338b9..080217c 100644
--- a/app/src/main/java/edu/sc/snacktrack/login/NewAccountFragment.java
+++ b/app/src/main/java/edu/sc/snacktrack/login/NewAccountFragment.java
@@ -8,6 +8,7 @@
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.text.Editable;
+import android.text.Html;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
@@ -45,7 +46,8 @@ public class NewAccountFragment extends Fragment {
private EditText passwordConfirmET;
private TextView usernameErrorStatus;
- private TextView passwordErrorStatus;
+ private TextView passwordMatchStatus;
+ private TextView passwordRequirementStatus;
private RadioGroup rGroup;
@@ -61,6 +63,8 @@ public class NewAccountFragment extends Fragment {
private boolean loggingIn;
+ private static final PasswordChecker passwordChecker = new PasswordChecker();
+
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -87,7 +91,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
passwordET = (EditText) view.findViewById(R.id.passwordEditText);
passwordConfirmET = (EditText) view.findViewById(R.id.passwordConfirmEditText);
usernameErrorStatus = (TextView) view.findViewById(R.id.usernameErrorStatus);
- passwordErrorStatus = (TextView) view.findViewById(R.id.passwordErrorStatus);
+ passwordMatchStatus = (TextView) view.findViewById(R.id.passwordMatchStatus);
+ passwordRequirementStatus = (TextView) view.findViewById(R.id.passwordReqTextView);
signUpButton = (Button) view.findViewById(R.id.signUpButton);
rGroup = (RadioGroup) view.findViewById(R.id.signUpRadioGroup);
existingAccountButton = (Button) view.findViewById(R.id.existingAccountButton);
@@ -142,82 +147,75 @@ private void attemptSignup(){
setWidgetsEnabled(false);
loggingIn = true;
+ final ParseUser newUser = new ParseUser();
+
String username = usernameET.getText().toString();
String password = passwordET.getText().toString();
String passwordConfirm = passwordConfirmET.getText().toString();
StringBuilder usernameInvalidReason = new StringBuilder();
- StringBuilder passwordInvalidReason = new StringBuilder();
+ StringBuilder passwordMatchReason = new StringBuilder();
StringBuilder selectionInvalidReason = new StringBuilder();
- // First check if the username is valid
- if(isUsernameValid(username, usernameInvalidReason)){
-
- // Next, check if the passwords are valid.
- if(isPasswordValid(password, passwordConfirm, passwordInvalidReason)){
-
- // Finally, check if a radio button was selected
- if(isSelected(selectionInvalidReason)) {
- final ParseUser newUser = new ParseUser();
- newUser.setUsername(username);
- newUser.setPassword(password);
-
- String sel = isDietitian();
+ if(!isUsernameValid(username, usernameInvalidReason)){
+ updateToast(usernameInvalidReason.toString(), Toast.LENGTH_LONG);
+ setWidgetsEnabled(true);
+ loggingIn = false;
+ return;
+ }
+ if(!doPasswordsMatch(password, passwordConfirm, passwordMatchReason)){
+ updateToast(passwordMatchReason.toString(), Toast.LENGTH_LONG);
+ setWidgetsEnabled(true);
+ loggingIn = false;
+ return;
+ }
+ if(!passwordChecker.meetsRequirements(password)){
+ updateToast("Password does not meet requirements", Toast.LENGTH_LONG);
+ setWidgetsEnabled(true);
+ loggingIn = false;
+ return;
+ }
+ if(!isSelected(selectionInvalidReason)){
+ updateToast(selectionInvalidReason.toString(), Toast.LENGTH_LONG);
+ setWidgetsEnabled(true);
+ loggingIn = false;
+ return;
+ }
- if(sel.equals("true"))
- newUser.put("isDietitian", true);
+ // If this line is reached, the provided credentials are valid, so we attempt sign up.
+ newUser.setUsername(username);
+ newUser.setPassword(password);
- else
- newUser.put("isDietitian", false);
+ String sel = isDietitian();
+ if(sel.equals("true"))
+ newUser.put("isDietitian", true);
+ else
+ newUser.put("isDietitian", false);
- newUser.signUpInBackground(new SignUpCallback() {
+ newUser.signUpInBackground(new SignUpCallback() {
+ @Override
+ public void done(ParseException e) {
+ if (e == null) {
+ // Sign up was successful
+ ParseRole role = new ParseRole("role_" + newUser.getObjectId());
+ role.setACL(new ParseACL(newUser));
+ role.saveInBackground(new SaveCallback() {
@Override
public void done(ParseException e) {
- if (e == null) {
- // Sign up was successful
- ParseRole role = new ParseRole("role_" + newUser.getObjectId());
- role.setACL(new ParseACL(newUser));
- role.saveInBackground(new SaveCallback() {
- @Override
- public void done(ParseException e) {
- if(e == null){
- startMainActivity();
- } else{
- updateToast(Utils.getErrorMessage(e), Toast.LENGTH_SHORT);
- }
- }
- });
- } else {
+ if(e == null){
+ startMainActivity();
+ } else{
updateToast(Utils.getErrorMessage(e), Toast.LENGTH_SHORT);
}
- setWidgetsEnabled(true);
- loggingIn = false;
}
});
+ } else {
+ updateToast(Utils.getErrorMessage(e), Toast.LENGTH_SHORT);
}
-
- // If no radio buttons are selected, display the reason to the user.
- else {
- updateToast(selectionInvalidReason.toString(), Toast.LENGTH_LONG);
- setWidgetsEnabled(true);
- loggingIn = false;
- }
- }
-
- // If the passwords are invalid, display the reason to the user.
- else{
- updateToast(passwordInvalidReason.toString(), Toast.LENGTH_LONG);
setWidgetsEnabled(true);
loggingIn = false;
}
- }
-
- // If the username is invalid, display the reason to the user
- else{
- updateToast(usernameInvalidReason.toString(), Toast.LENGTH_LONG);
- setWidgetsEnabled(true);
- loggingIn = false;
- }
+ });
}
/**
@@ -341,18 +339,16 @@ private boolean isUsernameValid(String username, @Nullable StringBuilder reason)
}
/**
- * Checks if passwords are valid.
- *
- * Currently this method only checks if the passwords match or if either is blank.
+ * Checks if a password and its confirmation match
*
* @param password The password
* @param passwordConfirm The confirmed password
- * @param reason When not null, this method will append the reason the password is invalid
- * (or "OK" if the username is valid).
- * @return true if the passwords are valid. false otherwise.
+ * @param reason When not null, this method will append the reason the passwords do not match
+ * (or "OK" if they do).
+ * @return true if the passwords match. false otherwise.
*/
- private boolean isPasswordValid(String password, String passwordConfirm,
- @Nullable StringBuilder reason){
+ private boolean doPasswordsMatch(String password, String passwordConfirm,
+ @Nullable StringBuilder reason){
if(password.equals("")){
if(reason != null){
reason.append("Password is blank");
@@ -411,21 +407,51 @@ private String isDietitian() {
}
/**
- * Updates the passwordErrorStatus based on a reason returned by isPasswordValid().
+ * Updates the password error status. That is, displays to the user whether or not the passwords
+ * match and if the password meets the strength requirements.
*/
private void updatePasswordErrorStatus(String password, String passwordConfirm){
- StringBuilder reason = new StringBuilder();
- String reasonString;
- isPasswordValid(password, passwordConfirm, reason);
- reasonString = reason.toString();
-
- if(reasonString.equalsIgnoreCase("OK")){
- passwordErrorStatus.setTextColor(Color.BLACK);
- passwordErrorStatus.setText(reasonString);
+ StringBuilder matchProblem = new StringBuilder();
+ if(doPasswordsMatch(password, passwordConfirm, matchProblem)){
+ passwordMatchStatus.setTextColor(Color.parseColor("#006600"));
+ passwordMatchStatus.setText("Passwords match");
} else{
- passwordErrorStatus.setTextColor(Color.RED);
- passwordErrorStatus.setText(reasonString);
+ passwordMatchStatus.setTextColor(Color.RED);
+ passwordMatchStatus.setText(matchProblem.toString());
}
+
+ PasswordChecker.CheckResult checkResult = PasswordChecker.checkPassword(password);
+
+ // Color each of the requirements red (requirement not satisfied) or green (requirement
+ // satisfied).
+ passwordRequirementStatus.setText(Html.fromHtml(new StringBuilder()
+ .append(checkResult.hasMixedCase() && checkResult.hasNumbers()
+ && checkResult.length() >= passwordChecker.getMinimumLength() ?
+ "Your password must: " :
+ "Your password must: "
+ )
+ .append(checkResult.hasMixedCase() && checkResult.hasNumbers() ?
+ "use " :
+ "use "
+ )
+ .append(checkResult.hasLowerCase() ?
+ "a lowercase letter, " :
+ "a lowercase letter, "
+ )
+ .append(checkResult.hasUpperCase() ?
+ "an uppercase letter, " :
+ "an uppercase letter, "
+ )
+ .append(checkResult.hasNumbers() ?
+ "a number, " :
+ "a number, "
+ )
+ .append(checkResult.length() >= passwordChecker.getMinimumLength() ?
+ "and have at least 8 characters." :
+ "and have at least 8 characters."
+ )
+ .toString()
+ ));
}
/**
diff --git a/app/src/main/java/edu/sc/snacktrack/login/PasswordChecker.java b/app/src/main/java/edu/sc/snacktrack/login/PasswordChecker.java
new file mode 100644
index 0000000..7685e02
--- /dev/null
+++ b/app/src/main/java/edu/sc/snacktrack/login/PasswordChecker.java
@@ -0,0 +1,168 @@
+package edu.sc.snacktrack.login;
+
+/**
+ * This class is a tool for checking the strength of passwords. A PasswordChecker holds the
+ * requirements of a password and can check which of those requirements a password meets.
+ */
+public class PasswordChecker {
+
+ public static final int DEFAULT_MINIMUM_LENGTH = 8;
+ public static final boolean DEFAULT_REQUIRE_LOWERCASE = true;
+ public static final boolean DEFAULT_REQUIRE_UPPERCASE = true;
+ public static final boolean DEFAULT_REQUIRE_NUMBERS = true;
+ public static final boolean DEFAULT_REQUIRE_SPECIAL_CHARS = false;
+
+ private static final String numbers = "0123456789";
+ private static final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ private int minimumLength;
+ private boolean requireLowercase;
+ private boolean requireUppercase;
+ private boolean requireNumbers;
+ private boolean requireSpecial;
+
+ /**
+ * Create a new password checker using the default values.
+ */
+ public PasswordChecker(){
+ minimumLength = DEFAULT_MINIMUM_LENGTH;
+ requireLowercase = DEFAULT_REQUIRE_LOWERCASE;
+ requireUppercase = DEFAULT_REQUIRE_UPPERCASE;
+ requireNumbers = DEFAULT_REQUIRE_NUMBERS;
+ requireSpecial = DEFAULT_REQUIRE_SPECIAL_CHARS;
+ }
+
+ // Standard getters and setters
+ public int getMinimumLength() {
+ return minimumLength;
+ }
+ public void setMinimumLength(int minimumLength) {
+ this.minimumLength = minimumLength;
+ }
+ public boolean isRequireSpecial() {
+ return requireSpecial;
+ }
+ public void setRequireSpecial(boolean requireSpecial) {
+ this.requireSpecial = requireSpecial;
+ }
+ public boolean isRequireNumbers() {
+ return requireNumbers;
+ }
+ public void setRequireNumbers(boolean requireNumbers) {
+ this.requireNumbers = requireNumbers;
+ }
+ public boolean isRequireUppercase() {
+ return requireUppercase;
+ }
+ public void setRequireUppercase(boolean requireUppercase) {
+ this.requireUppercase = requireUppercase;
+ }
+ public boolean isRequireLowercase() {
+ return requireLowercase;
+ }
+ public void setRequireLowercase(boolean requireLowercase) {
+ this.requireLowercase = requireLowercase;
+ }
+
+ /**
+ * Parses a password string and populates the fields specified in PasswordChecker.CheckResult.
+ *
+ * @param password The password to check
+ * @return The CheckResult
+ */
+ public static CheckResult checkPassword(String password){
+ CheckResult result = new CheckResult();
+
+ String passwordLowercase = password.toLowerCase();
+ String passwordUppercase = password.toUpperCase();
+
+ result.length = password.length();
+ result.hasLowerCase = !password.equals(passwordUppercase);
+ result.hasUpperCase = !password.equals(passwordLowercase);
+
+ for(char c1 : passwordUppercase.toCharArray()){
+ String str = Character.toString(c1);
+ if(alphabet.contains(str)){
+ result.hasLetters = true;
+ } else if(numbers.contains(str)){
+ result.hasNumbers = true;
+ } else{
+ result.hasSpecialCharacters = true;
+ }
+
+ // Break if all characters of interest have been found
+ if(result.hasLetters && result.hasSpecialCharacters && result.hasNumbers){
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Checks if a password meets the requirements of this password checker.
+ *
+ * @param password The password to check
+ * @return true if the password meets requirements. false otherwise.
+ */
+ public boolean meetsRequirements(String password){
+ CheckResult checkResult = checkPassword(password);
+ if(checkResult.length() < minimumLength){
+ return false;
+ } else if(requireLowercase && !checkResult.hasLowerCase()){
+ return false;
+ } else if(requireUppercase && !checkResult.hasUpperCase()){
+ return false;
+ } else if(requireNumbers && !checkResult.hasNumbers()){
+ return false;
+ } else if(requireSpecial && !checkResult.hasSpecialCharacters()){
+ return false;
+ } else{
+ return true;
+ }
+ }
+
+ /**
+ * This class holds the results of checking the strength of a password.
+ */
+ public static class CheckResult{
+
+ private boolean hasLowerCase;
+ private boolean hasUpperCase;
+ private boolean hasLetters;
+ private boolean hasNumbers;
+ private boolean hasSpecialCharacters;
+ private int length;
+
+ public CheckResult(){
+ hasLowerCase = false;
+ hasUpperCase = false;
+ hasNumbers = false;
+ hasSpecialCharacters = false;
+ length = 0;
+ }
+
+ // Standard getters
+ public boolean hasLowerCase(){
+ return hasLetters && hasLowerCase;
+ }
+ public boolean hasUpperCase(){
+ return hasLetters && hasUpperCase;
+ }
+ public boolean hasMixedCase(){
+ return hasUpperCase() && hasLowerCase();
+ }
+ public boolean hasLetters() {
+ return hasLetters;
+ }
+ public boolean hasNumbers(){
+ return hasNumbers;
+ }
+ public boolean hasSpecialCharacters(){
+ return hasSpecialCharacters;
+ }
+ public int length(){
+ return length;
+ }
+ }
+}
diff --git a/app/src/main/java/edu/sc/snacktrack/main/settings/ChangePasswordDialog.java b/app/src/main/java/edu/sc/snacktrack/main/settings/ChangePasswordDialog.java
index 078fdd6..51ed1cf 100644
--- a/app/src/main/java/edu/sc/snacktrack/main/settings/ChangePasswordDialog.java
+++ b/app/src/main/java/edu/sc/snacktrack/main/settings/ChangePasswordDialog.java
@@ -8,6 +8,10 @@
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
+import android.text.Editable;
+import android.text.Html;
+import android.text.TextWatcher;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -27,16 +31,21 @@
import edu.sc.snacktrack.login.LoginActivity;
import edu.sc.snacktrack.R;
+import edu.sc.snacktrack.login.PasswordChecker;
import edu.sc.snacktrack.utils.Utils;
public class ChangePasswordDialog extends DialogFragment {
private EditText passwordText;
private EditText passwordConfirmText;
+ private TextView passwordMatchStatus;
+ private TextView passwordReqStatus;
private Button submitButton;
private Button cancelButton;
public Context cont;
+ private static final PasswordChecker passwordChecker = new PasswordChecker();
+
public ChangePasswordDialog() {
//Empty constructor required
}
@@ -47,9 +56,59 @@ public void onAttach(Context context) {
cont = context;
}
+ /**
+ * Enables or disables all user input widgets.
+ *
+ * @param enabled true to enable; false to disable
+ */
private void setWidgetsEnabled(boolean enabled){
submitButton.setEnabled(enabled);
cancelButton.setEnabled(enabled);
+ passwordText.setEnabled(enabled);
+ passwordConfirmText.setEnabled(enabled);
+ }
+
+ /**
+ * Sets the text watchers for each of the EditTexts
+ */
+ private void setTextWatchers(){
+ passwordText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String password = passwordText.getText().toString();
+ String passwordConfirm = passwordConfirmText.getText().toString();
+ updatePasswordErrorStatus(password, passwordConfirm);
+ }
+ });
+
+ passwordConfirmText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String password = passwordText.getText().toString();
+ String passwordConfirm = passwordConfirmText.getText().toString();
+ updatePasswordErrorStatus(password, passwordConfirm);
+ }
+ });
}
@Override
@@ -60,9 +119,13 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
passwordText = (EditText) view.findViewById(R.id.password);
passwordConfirmText = (EditText) view.findViewById(R.id.confirmPassword);
+ passwordMatchStatus = (TextView) view.findViewById(R.id.passwordMatchStatus);
+ passwordReqStatus = (TextView) view.findViewById(R.id.passwordReqTextView);
submitButton = (Button) view.findViewById(R.id.new_password_submit);
cancelButton = (Button) view.findViewById(R.id.new_password_cancel);
+ setTextWatchers();
+
submitButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -77,111 +140,20 @@ public void onClick(View v) {
}
});
-//// final TextView tipText = (TextView) view.findViewById(R.id.password_tip);
-//// headerText = (TextView) view.findViewById(R.id.password_dialog);
-//// passwordText = (EditText) view.findViewById(R.id.new_password);
-// submitButton = (Button) view.findViewById(R.id.new_password_submit);
-// cancelButton = (Button) view.findViewById(R.id.new_password_cancel);
-//
-// submitButton.setEnabled(false);
-// submitButton.setTextColor(Color.parseColor("#FF6666"));
-//// tipText.setVisibility(View.GONE);
-//// tipText.setTextColor(Color.parseColor("#FFFFFF"));
-//
-// passwordText.setOnTouchListener(new View.OnTouchListener() {
-// @Override
-// public boolean onTouch(View v, MotionEvent event) {
-// v.setFocusable(true);
-// v.setFocusableInTouchMode(true);
-// return false;
-// }
-// });
-//
-// passwordText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-// @Override
-// public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-//
-// if (actionId == EditorInfo.IME_ACTION_DONE)
-// {
-// passwordText.setFocusable(false);
-//
-// if (passwordText.getText().length() != 0)
-// {
-// submitButton.setEnabled(true);
-// submitButton.setTextColor(Color.parseColor("#4DFF4D"));
-//// tipText.setVisibility(View.GONE);
-// headerText.setPadding(20,20,20,0);
-// }
-//
-// else
-// {
-//
-// submitButton.setEnabled(false);
-// headerText.setPadding(20,20,20,10);
-//// tipText.setVisibility(View.VISIBLE);
-//
-// ValueAnimator anim = new ValueAnimator();
-// anim.setIntValues(Color.parseColor("#FFFFFF"), Color.parseColor("#FF6666"));
-// anim.setEvaluator(new ArgbEvaluator());
-// anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-// @Override
-// public void onAnimationUpdate(ValueAnimator valueAnimator) {
-//// tipText.setTextColor((Integer) valueAnimator.getAnimatedValue());
-// }
-// });
-//
-// anim.setDuration(900);
-// anim.setRepeatCount(2);
-// anim.setRepeatMode(ValueAnimator.REVERSE);
-// anim.start();
-// }
-// }
-//
-// return false;
-// }
-// });
-//
-// //Submit changes and take user back to LoginActivity
-// submitButton.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-//
-// if(submitButton.isEnabled() == true)
-// {
-// Utils.closeSoftKeyboard(getContext(), v);
-// attemptPasswordChange();
-// Intent intent = new Intent(getActivity(),LoginActivity.class);
-// startActivity(intent);
-// dismiss();
-// }
-// }
-// });
-//
-// //Cancel changing password and dismiss dialogFragment
-// cancelButton.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// Utils.closeSoftKeyboard(getContext(), v);
-// dismiss();
-// }
-// });
-
return view;
}
/**
- * Checks if passwords are valid.
- *
- * Currently this method only checks if the passwords match or if either is blank.
+ * Checks if a password and its confirmation match
*
* @param password The password
* @param passwordConfirm The confirmed password
- * @param reason When not null, this method will append the reason the password is invalid
- * (or "OK" if the username is valid).
- * @return true if the passwords are valid. false otherwise.
+ * @param reason When not null, this method will append the reason the passwords do not match
+ * (or "OK" if they do).
+ * @return true if the passwords match. false otherwise.
*/
- private boolean isPasswordValid(String password, String passwordConfirm,
- @Nullable StringBuilder reason){
+ private boolean doPasswordsMatch(String password, String passwordConfirm,
+ @Nullable StringBuilder reason){
if(password.equals("")){
if(reason != null){
reason.append("Password is blank");
@@ -208,63 +180,128 @@ else if(!password.equals(passwordConfirm)){
}
}
+ /**
+ * Updates the password error status. That is, displays to the user whether or not the passwords
+ * match and if the password meets the strength requirements.
+ */
+ private void updatePasswordErrorStatus(String password, String passwordConfirm){
+ StringBuilder matchProblem = new StringBuilder();
+ if(doPasswordsMatch(password, passwordConfirm, matchProblem)){
+ passwordMatchStatus.setTextColor(Color.parseColor("#006600"));
+ passwordMatchStatus.setText("Passwords match");
+ } else{
+ passwordMatchStatus.setTextColor(Color.RED);
+ passwordMatchStatus.setText(matchProblem.toString());
+ }
+
+ PasswordChecker.CheckResult checkResult = PasswordChecker.checkPassword(password);
+
+ // Color each of the requirements red (requirement not satisfied) or green (requirement
+ // satisfied).
+ passwordReqStatus.setText(Html.fromHtml(new StringBuilder()
+ .append(checkResult.hasMixedCase() && checkResult.hasNumbers()
+ && checkResult.length() >= 8?
+ "Your password must: " :
+ "Your password must: "
+ )
+ .append(checkResult.hasMixedCase() && checkResult.hasNumbers() ?
+ "use " :
+ "use "
+ )
+ .append(checkResult.hasLowerCase() ?
+ "a lowercase letter, " :
+ "a lowercase letter, "
+ )
+ .append(checkResult.hasUpperCase() ?
+ "an uppercase letter, " :
+ "an uppercase letter, "
+ )
+ .append(checkResult.hasNumbers() ?
+ "a number, " :
+ "a number, "
+ )
+ .append(checkResult.length() >= passwordChecker.getMinimumLength() ?
+ "and have at least 8 characters." :
+ "and have at least 8 characters."
+ )
+ .toString()
+ ));
+ }
+
private void attemptPasswordChange() {
final String password = passwordText.getText().toString();
final String confirmPassword = passwordConfirmText.getText().toString();
final ParseUser currentUser = ParseUser.getCurrentUser();
- StringBuilder invalidReason = new StringBuilder();
-
- if(isPasswordValid(password, confirmPassword, invalidReason)){
- currentUser.setPassword(passwordText.getText().toString());
- setWidgetsEnabled(false);
- currentUser.saveInBackground(new SaveCallback() {
- @Override
- public void done(ParseException e) {
- if(e == null){
- ParseUser.logInInBackground(currentUser.getUsername(), password, new LogInCallback() {
- @Override
- public void done(ParseUser user, ParseException e) {
- if(e == null){
- Toast.makeText(
- cont,
- "Password change successful",
- Toast.LENGTH_SHORT
- ).show();
- dismiss();
- } else{
- Toast.makeText(
- cont,
- "Please reenter your credentials",
- Toast.LENGTH_LONG
- ).show();
- dismiss();
- if(getActivity() != null){
- getActivity().finish();
- Intent loginIntent = new Intent(cont, LoginActivity.class);
- startActivity(loginIntent);
- }
+ StringBuilder matchProblem = new StringBuilder();
+
+ if(!doPasswordsMatch(password, confirmPassword, matchProblem)){
+ if(cont != null){
+ Toast.makeText(
+ cont,
+ matchProblem.toString(),
+ Toast.LENGTH_LONG
+ ).show();
+ }
+ return;
+ }
+
+ if(!passwordChecker.meetsRequirements(password)){
+ if(cont != null){
+ Toast.makeText(
+ cont,
+ "Password does not meet requirements",
+ Toast.LENGTH_LONG
+ ).show();
+ }
+ return;
+ }
+
+ // If this line is reached, the provided credentials are valid, so we attempt the password
+ // change.
+
+ currentUser.setPassword(passwordText.getText().toString());
+ setWidgetsEnabled(false);
+ currentUser.saveInBackground(new SaveCallback() {
+ @Override
+ public void done(ParseException e) {
+ if(e == null){
+ ParseUser.logInInBackground(currentUser.getUsername(), password, new LogInCallback() {
+ @Override
+ public void done(ParseUser user, ParseException e) {
+ if(e == null){
+ Toast.makeText(
+ cont,
+ "Password change successful",
+ Toast.LENGTH_SHORT
+ ).show();
+ dismiss();
+ } else{
+ Toast.makeText(
+ cont,
+ "Password change successful - please reenter your new credentials",
+ Toast.LENGTH_LONG
+ ).show();
+ dismiss();
+ if(getActivity() != null){
+ getActivity().finish();
+ Intent loginIntent = new Intent(cont, LoginActivity.class);
+ startActivity(loginIntent);
}
- setWidgetsEnabled(true);
}
- });
- } else if(cont != null){
- Toast.makeText(
- cont,
- Utils.getErrorMessage(e),
- Toast.LENGTH_LONG
- ).show();
- setWidgetsEnabled(true);
- }
+ setWidgetsEnabled(true);
+ }
+ });
+ } else if(cont != null){
+ Toast.makeText(
+ cont,
+ Utils.getErrorMessage(e),
+ Toast.LENGTH_LONG
+ ).show();
+ setWidgetsEnabled(true);
}
- });
- } else if(cont != null){
- Toast.makeText(
- cont,
- invalidReason.toString(),
- Toast.LENGTH_LONG
- ).show();
- }
+ }
+ });
}
}
diff --git a/app/src/main/res/layout/fragment_new_account.xml b/app/src/main/res/layout/fragment_new_account.xml
index 46f00c9..c6bfc4b 100644
--- a/app/src/main/res/layout/fragment_new_account.xml
+++ b/app/src/main/res/layout/fragment_new_account.xml
@@ -40,15 +40,12 @@
android:inputType="textNoSuggestions" />
+ tools:text="isValid?" />
+ android:inputType="textPassword"
+ android:layout_below="@+id/passwordEditText"
+ android:layout_alignRight="@+id/passwordMatchStatus" />
+
+
+ android:minLines="2" />
diff --git a/app/src/main/res/layout/fragment_password_dialog.xml b/app/src/main/res/layout/fragment_password_dialog.xml
index d69ff05..9d8dd52 100644
--- a/app/src/main/res/layout/fragment_password_dialog.xml
+++ b/app/src/main/res/layout/fragment_password_dialog.xml
@@ -1,6 +1,7 @@
@@ -30,6 +31,22 @@
android:layout_height="wrap_content"
android:hint="Confirm new password"/>
+
+
+