diff --git a/app/build.gradle b/app/build.gradle index 72bd471..5857419 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,6 +19,9 @@ android { buildConfigField "String", "api_service_name", "\"ComunicAndroid\"" buildConfigField "String", "api_service_token", "\"5eQ8WGAeDTTyY\"" + //Links to Comunic pages + buildConfigField "String", "comunic_terms_url", "\"http://devweb.local:4000/about/terms/\"" + //Connexion to Crash Reporter buildConfigField "String", "crash_reporter_url", "\"http://devweb.local/CrashReporterWeb/project/api/v1/push\"" buildConfigField "String", "crash_reporter_key", "\"KSyqOzkfJasDTxE0wrXYnUPl8dV1veBc\"" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bee94cd..f724c69 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -29,6 +29,11 @@ android:name=".ui.activities.LoginActivity" android:label="@string/activity_login_header" /> + + + + android:label="@string/title_activity_settings" /> + \ No newline at end of file diff --git a/app/src/main/java/org/communiquons/android/comunic/client/data/asynctasks/SafeAsyncTask.java b/app/src/main/java/org/communiquons/android/comunic/client/data/asynctasks/SafeAsyncTask.java new file mode 100644 index 0000000..a7c93da --- /dev/null +++ b/app/src/main/java/org/communiquons/android/comunic/client/data/asynctasks/SafeAsyncTask.java @@ -0,0 +1,77 @@ +package org.communiquons.android.comunic.client.data.asynctasks; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.AsyncTask; + +/** + * Safe async task (can be used statically) + * + * @param Params object type + * @param Progress object type + * @param Result object type + */ +public abstract class SafeAsyncTask + extends AsyncTask { + + private OnPostExecuteListener onPostExecuteListener = null; + + /** + * Application context + */ + @SuppressLint("StaticFieldLeak") + private Context context; + + /** + * Public constructor of the object + * + * @param context The context of the activity / fragment / application + */ + public SafeAsyncTask(Context context){ + super(); + + //Save application context + this.context = context.getApplicationContext(); + } + + /** + * @return Application context + */ + public Context getContext() { + return context; + } + + /** + * Set (replace) onPostExecuteListener + * + * @param onPostExecuteListener New listener + */ + public void setOnPostExecuteListener(OnPostExecuteListener onPostExecuteListener) { + this.onPostExecuteListener = onPostExecuteListener; + } + + @Override + protected void onPostExecute(Result result) { + super.onPostExecute(result); + + if(onPostExecuteListener != null) + onPostExecuteListener.OnPostExecute(result); + } + + /** + * This interface is used to update what is done once the task is finished while the task + * is running + * + * @param The kind of reslt + */ + public interface OnPostExecuteListener { + + /** + * Executed once the task is finished + * + * @param result The result of the operation + */ + void OnPostExecute(Result result); + + } +} diff --git a/app/src/main/java/org/communiquons/android/comunic/client/data/helpers/AccountHelper.java b/app/src/main/java/org/communiquons/android/comunic/client/data/helpers/AccountHelper.java index 4b2167b..f9352e4 100644 --- a/app/src/main/java/org/communiquons/android/comunic/client/data/helpers/AccountHelper.java +++ b/app/src/main/java/org/communiquons/android/comunic/client/data/helpers/AccountHelper.java @@ -3,6 +3,9 @@ package org.communiquons.android.comunic.client.data.helpers; import android.content.Context; import android.util.Log; +import org.communiquons.android.comunic.client.data.models.APIRequest; +import org.communiquons.android.comunic.client.data.models.APIResponse; +import org.communiquons.android.comunic.client.data.models.NewAccount; import org.communiquons.android.comunic.client.data.utils.Utilities; import org.json.JSONArray; import org.json.JSONException; @@ -178,4 +181,29 @@ public class AccountHelper { //Success return true; } + + /** + * Create a new account + * + * @param newAccount Information about the new account to create + * @return TRUE for a success / FALSE else + */ + public boolean createAccount(NewAccount newAccount) { + + APIRequest request = new APIRequest(mContext, "account/create"); + request.addString("firstName", newAccount.getFirstName()); + request.addString("lastName", newAccount.getLastName()); + request.addString("emailAddress", newAccount.getEmail()); + request.addString("password", newAccount.getPassword()); + + //Perform the request + try { + APIResponse response = new APIRequestHelper().exec(request); + return response.getResponse_code() == 200; + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } } diff --git a/app/src/main/java/org/communiquons/android/comunic/client/data/models/NewAccount.java b/app/src/main/java/org/communiquons/android/comunic/client/data/models/NewAccount.java new file mode 100644 index 0000000..268f57b --- /dev/null +++ b/app/src/main/java/org/communiquons/android/comunic/client/data/models/NewAccount.java @@ -0,0 +1,47 @@ +package org.communiquons.android.comunic.client.data.models; + +/** + * New account model + * + * @author Pierre HUBERT + */ +public class NewAccount { + + //Private fields + private String firstName; + private String lastName; + private String email; + private String password; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/app/src/main/java/org/communiquons/android/comunic/client/data/utils/Utilities.java b/app/src/main/java/org/communiquons/android/comunic/client/data/utils/Utilities.java index fbc7e44..6b8daf3 100644 --- a/app/src/main/java/org/communiquons/android/comunic/client/data/utils/Utilities.java +++ b/app/src/main/java/org/communiquons/android/comunic/client/data/utils/Utilities.java @@ -116,7 +116,7 @@ public class Utilities { * @param mail The E-Mail address to check * @return True if the mail is valid / false else */ - public boolean isValidMail(CharSequence mail){ + public static boolean isValidMail(CharSequence mail){ return !TextUtils.isEmpty(mail) && Patterns.EMAIL_ADDRESS.matcher(mail).matches(); } diff --git a/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/CreateAccountActivity.java b/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/CreateAccountActivity.java new file mode 100644 index 0000000..697de2f --- /dev/null +++ b/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/CreateAccountActivity.java @@ -0,0 +1,276 @@ +package org.communiquons.android.comunic.client.ui.activities; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.TextView; + +import org.communiquons.android.comunic.client.BuildConfig; +import org.communiquons.android.comunic.client.R; +import org.communiquons.android.comunic.client.data.asynctasks.SafeAsyncTask; +import org.communiquons.android.comunic.client.data.helpers.AccountHelper; +import org.communiquons.android.comunic.client.data.models.NewAccount; +import org.communiquons.android.comunic.client.data.utils.Utilities; + +import static android.os.AsyncTask.Status.FINISHED; + +/** + * Create account activity + * + * @author Pierre HUBERT + */ +public class CreateAccountActivity extends AppCompatActivity + implements SafeAsyncTask.OnPostExecuteListener { + + /** + * Input fields + */ + private ProgressBar mProgress; + private View mForm; + private TextView mError; + private EditText mFirstName; + private EditText mLastName; + private EditText mEmailAddress; + private EditText mPassword; + private EditText mRepeatPassword; + private CheckBox mTermsCheckbox; + private TextView mTermsLink; + private Button mSubmitButton; + + /** + * Create account task + */ + private static CreateAccountTask mCreateAccountTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create_account); + + //Display backward arrow + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + //Get the views + mProgress = findViewById(R.id.loading_progress); + mForm = findViewById(R.id.create_account_form); + mError = findViewById(R.id.error_target); + mFirstName = findViewById(R.id.first_name); + mLastName = findViewById(R.id.last_name); + mEmailAddress = findViewById(R.id.email); + mPassword = findViewById(R.id.password); + mRepeatPassword = findViewById(R.id.confirm_password); + mTermsCheckbox = findViewById(R.id.terms_checkbox); + mTermsLink = findViewById(R.id.terms_link); + mSubmitButton = findViewById(R.id.submit_button); + + //Remove error text + setError(""); + + //Make terms link lives + mTermsLink.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse(BuildConfig.comunic_terms_url)); + startActivity(intent); + } + }); + + mSubmitButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + submitForm(); + } + }); + + //Check if a request to create an account is running or not + if(isCreating()){ + mCreateAccountTask.setOnPostExecuteListener(this); + setLoading(true); + } + else + setLoading(false); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + if(item.getItemId() == android.R.id.home){ + finish(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + private void submitForm(){ + + if(isCreating()) + return; + + //Reset errors + setError(""); + mFirstName.setError(null); + mLastName.setError(null); + mEmailAddress.setError(null); + mPassword.setError(null); + mRepeatPassword.setError(null); + mTermsCheckbox.setError(null); + + //Get the values + String firstName = mFirstName.getText().toString(); + String lastName = mLastName.getText().toString(); + String email = mEmailAddress.getText().toString(); + String password = mPassword.getText().toString(); + String confirmPassword = mRepeatPassword.getText().toString(); + + //Check values + boolean cancel = false; + View focusView = null; + + //Check first name + if(firstName.length() < 2){ + mFirstName.setError(getString(R.string.err_invalid_first_name)); + cancel = true; + focusView = mFirstName; + } + + //Check last name + if(lastName.length() < 2){ + mLastName.setError(getString(R.string.err_invalid_last_name)); + cancel = true; + focusView = focusView != null ? focusView : mLastName; + } + + //Check email address + if(email.isEmpty()){ + mEmailAddress.setError(getString(R.string.err_no_email)); + cancel = true; + focusView = focusView != null ? focusView : mEmailAddress; + } + else if(!Utilities.isValidMail(email)){ + mEmailAddress.setError(getString(R.string.err_invalid_email)); + cancel = true; + focusView = focusView != null ? focusView : mEmailAddress; + } + + //Check password + if(password.length() < 4){ + mPassword.setError(getString(R.string.err_invalid_password)); + cancel = true; + focusView = focusView != null ? focusView : mPassword; + } else if(!password.equals(confirmPassword)){ + mRepeatPassword.setError(getString(R.string.err_password_confirmation_not_identical)); + cancel = true; + focusView = focusView != null ? focusView : mRepeatPassword; + } + + //Check the terms + if(!mTermsCheckbox.isChecked()){ + mTermsCheckbox.setError(getString(R.string.err_need_accept_terms)); + cancel = true; + focusView = focusView != null ? focusView : mTermsCheckbox; + } + + //Check if we can not continue + if(cancel){ + if(focusView != null) + focusView.requestFocus(); + return; + } + + //Submit request + NewAccount newAccount = new NewAccount(); + newAccount.setFirstName(firstName); + newAccount.setLastName(lastName); + newAccount.setEmail(email); + newAccount.setPassword(password); + + //Initialize task + mCreateAccountTask = new CreateAccountTask(this); + mCreateAccountTask.setOnPostExecuteListener(this); + mCreateAccountTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, newAccount); + + //Mark the task as running + setLoading(true); + } + + /** + * Check whether an account creation request has already been sent or not + * + * @return TRUE if a request is running / FALSE else + */ + private boolean isCreating() { + if (mCreateAccountTask == null) + return false; + + return !mCreateAccountTask.isCancelled() && mCreateAccountTask.getStatus() != FINISHED; + + } + + /** + * Set the task as loading + * + * @param loading TRUE if the task is running / FALSE else + */ + private void setLoading(boolean loading){ + mForm.setVisibility(loading ? View.GONE : View.VISIBLE); + mProgress.setVisibility(loading ? View.VISIBLE : View.GONE); + } + + /** + * Set a new error message + * + * @param message The new error message to display + */ + private void setError(String message){ + mError.setVisibility(message.isEmpty() ? View.GONE : View.VISIBLE); + mError.setText(message); + } + + @Override + public void OnPostExecute(Boolean result) { + setLoading(false); + + //Check for errors + if(!result){ + setError(getString(R.string.err_while_creating_account)); + return; + } + + //In case of success, inflate a new view + setContentView(R.layout.activity_account_created); + + findViewById(R.id.sign_in_button).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + finish(); + } + }); + } + + /** + * Class used to create an account across activities + */ + private static class CreateAccountTask extends SafeAsyncTask { + + CreateAccountTask(Context context) { + super(context); + } + + @Override + protected Boolean doInBackground(NewAccount... newAccounts) { + return new AccountHelper(getContext()).createAccount(newAccounts[0]); + } + + } +} diff --git a/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/LoginActivity.java b/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/LoginActivity.java index e5f9e9f..33971d9 100644 --- a/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/LoginActivity.java +++ b/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/LoginActivity.java @@ -31,11 +31,6 @@ import java.util.ArrayList; public class LoginActivity extends AppCompatActivity { - /** - * Utilities object - */ - private Utilities utils; - /** * Account utilities object */ @@ -48,9 +43,6 @@ public class LoginActivity extends AppCompatActivity { assert getSupportActionBar() != null; getSupportActionBar().hide(); - //Create utilities object - utils = new Utilities(this); - //Create account utilities object aUtils = new AccountUtils(this); @@ -69,6 +61,15 @@ public class LoginActivity extends AppCompatActivity { }); + //Make create account button lives + findViewById(R.id.btn_create_account).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(LoginActivity.this, + CreateAccountActivity.class); + startActivity(intent); + } + }); } @Override @@ -100,7 +101,7 @@ public class LoginActivity extends AppCompatActivity { } //Check email address - if(login_mail.length() < 3 || !utils.isValidMail(login_mail.getText())){ + if(login_mail.length() < 3 || !Utilities.isValidMail(login_mail.getText())){ login_mail.setError(getString(R.string.activity_login_err_invalid_email)); login_mail.requestFocus(); stop = 1; diff --git a/app/src/main/res/layout/activity_account_created.xml b/app/src/main/res/layout/activity_account_created.xml new file mode 100644 index 0000000..e9be847 --- /dev/null +++ b/app/src/main/res/layout/activity_account_created.xml @@ -0,0 +1,50 @@ + + + + + + + +