Can create an account.

This commit is contained in:
Pierre HUBERT 2018-08-07 10:56:25 +02:00
parent 67c4878e95
commit 5e754f24bc
13 changed files with 712 additions and 11 deletions

View File

@ -19,6 +19,9 @@ android {
buildConfigField "String", "api_service_name", "\"ComunicAndroid\"" buildConfigField "String", "api_service_name", "\"ComunicAndroid\""
buildConfigField "String", "api_service_token", "\"5eQ8WGAeDTTyY\"" 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 //Connexion to Crash Reporter
buildConfigField "String", "crash_reporter_url", "\"http://devweb.local/CrashReporterWeb/project/api/v1/push\"" buildConfigField "String", "crash_reporter_url", "\"http://devweb.local/CrashReporterWeb/project/api/v1/push\""
buildConfigField "String", "crash_reporter_key", "\"KSyqOzkfJasDTxE0wrXYnUPl8dV1veBc\"" buildConfigField "String", "crash_reporter_key", "\"KSyqOzkfJasDTxE0wrXYnUPl8dV1veBc\""

View File

@ -29,6 +29,11 @@
android:name=".ui.activities.LoginActivity" android:name=".ui.activities.LoginActivity"
android:label="@string/activity_login_header" /> android:label="@string/activity_login_header" />
<!-- Create account activity -->
<activity
android:name=".ui.activities.CreateAccountActivity"
android:label="@string/activity_create_account_label"/>
<!-- Search user activity --> <!-- Search user activity -->
<activity <activity
android:name=".ui.activities.SearchUserActivity" android:name=".ui.activities.SearchUserActivity"
@ -48,6 +53,7 @@
<activity <activity
android:name=".ui.activities.SettingsActivity" android:name=".ui.activities.SettingsActivity"
android:label="@string/title_activity_settings" /> android:label="@string/title_activity_settings" />
</application> </application>
</manifest> </manifest>

View File

@ -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> Params object type
* @param <Progress> Progress object type
* @param <Result> Result object type
*/
public abstract class SafeAsyncTask<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result> {
private OnPostExecuteListener<Result> 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<Result> 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 <Result> The kind of reslt
*/
public interface OnPostExecuteListener<Result> {
/**
* Executed once the task is finished
*
* @param result The result of the operation
*/
void OnPostExecute(Result result);
}
}

View File

@ -3,6 +3,9 @@ package org.communiquons.android.comunic.client.data.helpers;
import android.content.Context; import android.content.Context;
import android.util.Log; 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.communiquons.android.comunic.client.data.utils.Utilities;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -178,4 +181,29 @@ public class AccountHelper {
//Success //Success
return true; 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;
}
}
} }

View File

@ -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;
}
}

View File

@ -116,7 +116,7 @@ public class Utilities {
* @param mail The E-Mail address to check * @param mail The E-Mail address to check
* @return True if the mail is valid / false else * @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(); return !TextUtils.isEmpty(mail) && Patterns.EMAIL_ADDRESS.matcher(mail).matches();
} }

View File

@ -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<Boolean> {
/**
* 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<NewAccount, Void, Boolean> {
CreateAccountTask(Context context) {
super(context);
}
@Override
protected Boolean doInBackground(NewAccount... newAccounts) {
return new AccountHelper(getContext()).createAccount(newAccounts[0]);
}
}
}

View File

@ -31,11 +31,6 @@ import java.util.ArrayList;
public class LoginActivity extends AppCompatActivity { public class LoginActivity extends AppCompatActivity {
/**
* Utilities object
*/
private Utilities utils;
/** /**
* Account utilities object * Account utilities object
*/ */
@ -48,9 +43,6 @@ public class LoginActivity extends AppCompatActivity {
assert getSupportActionBar() != null; assert getSupportActionBar() != null;
getSupportActionBar().hide(); getSupportActionBar().hide();
//Create utilities object
utils = new Utilities(this);
//Create account utilities object //Create account utilities object
aUtils = new AccountUtils(this); 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 @Override
@ -100,7 +101,7 @@ public class LoginActivity extends AppCompatActivity {
} }
//Check email address //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.setError(getString(R.string.activity_login_err_invalid_email));
login_mail.requestFocus(); login_mail.requestFocus();
stop = 1; stop = 1;

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/activity_login_bg">
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:text="@string/account_created_title"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:textColor="@android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:text="@string/account_created_message"
android:textAlignment="center"
android:textColor="@android:color/background_light"
app:layout_constraintBottom_toTopOf="@+id/sign_in_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4" />
<Button
android:id="@+id/sign_in_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="@string/account_created_sign_in"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/loading_progress"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true" />
<!-- Account creation form -->
<ScrollView
android:id="@+id/create_account_form"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/activity_login_bg">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
style="@style/TextGeneralStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:text="@string/form_create_account_notice"
android:textAlignment="center" />
<TextView
android:id="@+id/error_target"
style="@style/CreateAccountError"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="An error occurred while creating the account !" />
<android.support.design.widget.TextInputLayout
style="@style/TextGeneralStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/first_name"
style="@style/CreateAccountInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/form_create_account_first_name" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
style="@style/TextGeneralStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/last_name"
style="@style/CreateAccountInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/form_create_account_last_name" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
style="@style/TextGeneralStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/email"
style="@style/CreateAccountInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/form_create_account_email"
android:inputType="textEmailAddress" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
style="@style/TextGeneralStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/password"
style="@style/CreateAccountInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/form_create_account_password"
android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
style="@style/TextGeneralStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/confirm_password"
style="@style/CreateAccountInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/form_create_account_confirm_password"
android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<CheckBox
android:id="@+id/terms_checkbox"
style="@style/CreateAccountInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
style="@style/CreateAccountInput"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:maxLines="10"
android:singleLine="false"
android:text="@string/form_create_account_terms" />
<TextView
android:id="@+id/terms_link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="20dp"
android:paddingStart="10dp"
android:text="@string/form_create_account_terms_open"
android:textColor="@android:color/white"
android:textStyle="bold" />
</LinearLayout>
<Button
android:id="@+id/submit_button"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/action_create_account"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
</RelativeLayout>

View File

@ -102,6 +102,14 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:text="@string/activity_login_submit_form"/> android:text="@string/activity_login_submit_form"/>
<Button
android:id="@+id/btn_create_account"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/action_create_account" />
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@ -211,4 +211,25 @@
<string name="notif_rejected_group_membership_request">rejected your request to join the group</string> <string name="notif_rejected_group_membership_request">rejected your request to join the group</string>
<string name="preference_crash_reporting_title">Send crash reports</string> <string name="preference_crash_reporting_title">Send crash reports</string>
<string name="preference_crash_reporting_summary">Help us improve Comunic by sending anonymous reports when the application crash.</string> <string name="preference_crash_reporting_summary">Help us improve Comunic by sending anonymous reports when the application crash.</string>
<string name="action_create_account">Create an account</string>
<string name="activity_create_account_label">New account</string>
<string name="form_create_account_notice">Please fill the following fields to create your account:</string>
<string name="form_create_account_first_name">First name</string>
<string name="form_create_account_last_name">Last name</string>
<string name="form_create_account_email">Your email address</string>
<string name="form_create_account_password">Password</string>
<string name="form_create_account_confirm_password">Repeat password</string>
<string name="form_create_account_terms">I have read and accepted the terms of use of Comunic.</string>
<string name="form_create_account_terms_open">Open</string>
<string name="err_invalid_first_name">Specified first name is invalid!</string>
<string name="err_invalid_last_name">Please specify a valid last name.</string>
<string name="err_no_email">Please specify an email address!</string>
<string name="err_invalid_email">Please specify a valid email address!</string>
<string name="err_invalid_password">Please specify a valid password!</string>
<string name="err_password_confirmation_not_identical">The password and its confirmation are not the same!</string>
<string name="err_need_accept_terms">Please accept the terms of use of Comunic !</string>
<string name="err_while_creating_account">An error occurred while trying to create your account! Maybe an account with the same email address already exists!</string>
<string name="account_created_title">Congratulations</string>
<string name="account_created_message">Your account has been created. You can now sign into your new account to use all the features of Comunic.</string>
<string name="account_created_sign_in">Sign in</string>
</resources> </resources>

View File

@ -21,6 +21,31 @@
<item name="android:textColorHighlight">@android:color/white</item> <item name="android:textColorHighlight">@android:color/white</item>
</style> </style>
<!-- Create account activity -->
<!-- Error -->
<style name="CreateAccountError">
<item name="android:textColor">@android:color/holo_red_light</item>
<item name="android:textAlignment">center</item>
</style>
<!-- Texts general style -->
<style name="TextGeneralStyle">
<item name="android:textColor">@android:color/white</item>
<item name="android:textColorHint">@android:color/white</item>
<item name="android:textColorLink">@android:color/white</item>
<item name="android:textColorHighlight">@android:color/white</item>
</style>
<!-- Inputs general style -->
<style name="CreateAccountInput" parent="TextGeneralStyle">
<item name="android:maxLines">1</item>
<item name="android:singleLine">true</item>
<item name="android:layout_marginBottom">5dp</item>
</style>
<!-- User page fragment --> <!-- User page fragment -->
<!-- User page header --> <!-- User page header -->
<style name="UserPageHeader"> <style name="UserPageHeader">