package yuku.alkitab.base.sync; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.text.method.LinkMovementMethod; import android.util.Log; import android.util.Patterns; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; import yuku.afw.V; import yuku.afw.widget.EasyAdapter; import yuku.alkitab.base.App; import yuku.alkitab.base.U; import yuku.alkitab.base.ac.base.BaseActivity; import yuku.alkitab.base.util.Background; import yuku.alkitab.debug.R; public class SyncLoginActivity extends BaseActivity { public static class Result { public String accountName; public String simpleToken; } public static Intent createIntent() { return new Intent(App.context, SyncLoginActivity.class); } public static Result obtainResult(final Intent data) { if (data == null) return null; final Result res = new Result(); res.accountName = data.getStringExtra("accountName"); res.simpleToken = data.getStringExtra("simpleToken"); return res; } TextView tIntro; EditText tEmail; EditText tPassword; EditText tPasswordNew; Button bForgot; View panelRegister; EditText tChurch; EditText tCity; Spinner cbReligion; TextView tPrivacy; Button bRegister; Button bLogin; Button bChangePassword; ReligionAdapter religionAdapter; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sync_login); final Toolbar toolbar = V.get(this, R.id.toolbar); setSupportActionBar(toolbar); final ActionBar ab = getSupportActionBar(); assert ab != null; ab.setDisplayHomeAsUpEnabled(true); tIntro = V.get(this, R.id.tIntro); tEmail = V.get(this, R.id.tEmail); tPassword = V.get(this, R.id.tPassword); tPasswordNew = V.get(this, R.id.tPasswordNew); bForgot = V.get(this, R.id.bForgot); panelRegister = V.get(this, R.id.panelRegister); tChurch = V.get(this, R.id.tChurch); tCity = V.get(this, R.id.tCity); cbReligion = V.get(this, R.id.cbReligion); tPrivacy = V.get(this, R.id.tPrivacy); bRegister = V.get(this, R.id.bRegister); bLogin = V.get(this, R.id.bLogin); bChangePassword = V.get(this, R.id.bChangePassword); cbReligion.setAdapter(religionAdapter = new ReligionAdapter()); panelRegister.setVisibility(View.GONE); panelRegister.setTag(/* opened: */ false); bRegister.setOnClickListener(v -> { if (Boolean.FALSE.equals(panelRegister.getTag())) { panelRegister.setVisibility(View.VISIBLE); panelRegister.setTag(/* opened: */ true); bLogin.setVisibility(View.GONE); return; } final String email = tEmail.getText().toString().trim(); if (email.length() == 0) { tEmail.setError(getString(R.string.sync_login_form_error_required)); return; } else if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) { tEmail.setError(getString(R.string.sync_login_form_error_email_pattern)); return; } else { tEmail.setError(null); } if (tPassword.length() == 0) { tPassword.setError(getString(R.string.sync_login_form_error_required)); return; } else { tPassword.setError(null); } final String password = tPassword.getText().toString(); confirmPassword(password, () -> { final String religion = (String) cbReligion.getSelectedItem(); final String city = tCity.length() == 0 ? null : tCity.getText().toString().trim(); final String church = tChurch.length() == 0 ? null : tChurch.getText().toString().trim(); final Sync.RegisterForm form = new Sync.RegisterForm(); form.email = email; form.password = password; form.city = city; form.church = church; form.religion = religion; startThreadWithProgressDialog(getString(R.string.sync_progress_register), () -> { try { Log.d(TAG, "Sending form to server for creating new account..."); SyncRecorder.log(SyncRecorder.EventKind.register_attempt, null, "serverPrefix", Sync.getEffectiveServerPrefix(), "email", email); final Sync.LoginResponseJson response = Sync.register(form); gotSimpleToken(email, response.simpleToken, true); } catch (Sync.NotOkException e) { Log.d(TAG, "Register failed: " + e.getMessage()); SyncRecorder.log(SyncRecorder.EventKind.register_failed, null, "email", email, "message", e.getMessage()); runOnUiThread(() -> new MaterialDialog.Builder(this) .content(getString(R.string.sync_register_failed_with_reason, e.getMessage())) .positiveText(R.string.ok) .show() ); } }); }); }); bLogin.setOnClickListener(v -> { final String email = tEmail.getText().toString().trim(); if (email.length() == 0) { tEmail.setError(getString(R.string.sync_login_form_error_required)); return; } else if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) { tEmail.setError(getString(R.string.sync_login_form_error_email_pattern)); return; } else { tEmail.setError(null); } if (tPassword.length() == 0) { tPassword.setError(getString(R.string.sync_login_form_error_required)); return; } else { tPassword.setError(null); } final String password = tPassword.getText().toString(); startThreadWithProgressDialog(getString(R.string.sync_progress_login), () -> { try { Log.d(TAG, "Sending form to server for login..."); SyncRecorder.log(SyncRecorder.EventKind.login_attempt, null, "serverPrefix", Sync.getEffectiveServerPrefix(), "email", email); final Sync.LoginResponseJson response = Sync.login(email, password); gotSimpleToken(email, response.simpleToken, false); } catch (Sync.NotOkException e) { Log.d(TAG, "Login failed: " + e.getMessage()); SyncRecorder.log(SyncRecorder.EventKind.login_failed, null, "email", email, "message", e.getMessage()); runOnUiThread(() -> new MaterialDialog.Builder(this) .content(getString(R.string.sync_login_failed_with_reason, e.getMessage())) .positiveText(R.string.ok) .show() ); } }); }); tPassword.setOnFocusChangeListener((v, hasFocus) -> bForgot.setVisibility(tPassword.length() > 0 || hasFocus ? View.GONE : View.VISIBLE)); bForgot.setOnClickListener(v -> { final String email = tEmail.getText().toString().trim(); if (email.length() == 0) { tEmail.setError(getString(R.string.sync_login_form_error_required)); return; } else { tEmail.setError(null); } startThreadWithProgressDialog(getString(R.string.sync_progress_processing), () -> { try { Log.d(TAG, "Sending form to server for forgot password..."); Sync.forgotPassword(email); runOnUiThread(() -> new MaterialDialog.Builder(this) .content(R.string.sync_login_form_forgot_password_success) .positiveText(R.string.ok) .show() ); } catch (Sync.NotOkException e) { Log.d(TAG, "Forgot password failed: " + e.getMessage()); runOnUiThread(() -> new MaterialDialog.Builder(this) .content(e.getMessage()) .positiveText(R.string.ok) .show() ); } }); }); bChangePassword.setOnClickListener(v -> { final String email = tEmail.getText().toString().trim(); if (email.length() == 0) { tEmail.setError(getString(R.string.sync_login_form_error_required)); return; } else { tEmail.setError(null); } final String password = tPassword.getText().toString(); if (password.length() == 0) { tPassword.setError(getString(R.string.sync_login_form_error_required)); return; } else { tPassword.setError(null); } final String passwordNew = tPasswordNew.getText().toString(); if (passwordNew.length() == 0) { tPasswordNew.setError(getString(R.string.sync_login_form_error_required)); return; } else { tPasswordNew.setError(null); } confirmPassword(passwordNew, () -> startThreadWithProgressDialog(getString(R.string.sync_progress_processing), () -> { try { Log.d(TAG, "Sending form to server for changing password..."); Sync.changePassword(email, password, passwordNew); runOnUiThread(() -> new MaterialDialog.Builder(this) .content(R.string.sync_login_form_change_password_success) .positiveText(R.string.ok) .show() .setOnDismissListener(dialog -> finish()) ); } catch (Sync.NotOkException e) { Log.d(TAG, "Change password failed: " + e.getMessage()); runOnUiThread(() -> new MaterialDialog.Builder(this) .content(e.getMessage()) .positiveText(R.string.ok) .show() ); } })); }); tIntro.setMovementMethod(LinkMovementMethod.getInstance()); tPrivacy.setMovementMethod(LinkMovementMethod.getInstance()); } void startThreadWithProgressDialog(final String message, final Runnable task) { final MaterialDialog pd = new MaterialDialog.Builder(this) .content(message) .cancelable(false) .progress(true, 0) .show(); Background.run(() -> { try { task.run(); } finally { pd.dismiss(); } }); } void confirmPassword(final String correctPassword, final Runnable whenCorrect) { new MaterialDialog.Builder(this) .customView(R.layout.dialog_sync_confirm_password, false) .positiveText(R.string.ok) .onPositive((dialog, which) -> { final EditText tPassword2 = V.get(dialog.getCustomView(), R.id.tPassword2); final String password2 = tPassword2.getText().toString(); if (!U.equals(correctPassword, password2)) { new MaterialDialog.Builder(dialog.getContext()) .content(R.string.sync_login_form_passwords_do_not_match) .positiveText(R.string.ok) .show(); return; } whenCorrect.run(); }) .show(); } @Override public boolean onCreateOptionsMenu(final Menu menu) { getMenuInflater().inflate(R.menu.activity_sync_login, menu); return true; } @Override public boolean onOptionsItemSelected(final MenuItem item) { final int itemId = item.getItemId(); switch (itemId) { case R.id.menuChangePassword: bLogin.setVisibility(View.GONE); bRegister.setVisibility(View.GONE); bChangePassword.setVisibility(View.VISIBLE); tPasswordNew.setVisibility(View.VISIBLE); panelRegister.setVisibility(View.GONE); return true; case R.id.menuSyncLog: startActivity(SyncLogActivity.createIntent()); return true; } return super.onOptionsItemSelected(item); } /** * We created account or logged in successfully. Call this method from a background thread! * Close this activity and report success. */ void gotSimpleToken(final String accountName, final String simpleToken, final boolean isRegister) { // send GCM registration id, if we already have it. final String registration_id = Gcm.renewGcmRegistrationIdIfNeeded(Sync::notifyNewGcmRegistrationId); if (registration_id != null) { final boolean ok = Sync.sendGcmRegistrationId(simpleToken, registration_id); if (!ok) { SyncRecorder.log(SyncRecorder.EventKind.login_gcm_sending_failed, null, "accountName", accountName); if (isRegister) { runOnUiThread(() -> new MaterialDialog.Builder(this) .content(R.string.sync_registered_but_no_gcm) .positiveText(R.string.ok) .show()); } else { runOnUiThread(() -> new MaterialDialog.Builder(this) .content(getString(R.string.sync_login_failed_with_reason, "Could not send GCM registration id. Please try again.")) .positiveText(R.string.ok) .show()); } return; } } else { // if not, ignore. Later eventually we will have it. SyncRecorder.log(SyncRecorder.EventKind.login_gcm_not_possessed_yet, null, "accountName", accountName); } runOnUiThread(() -> { final Intent data = new Intent(); data.putExtra("accountName", accountName); data.putExtra("simpleToken", simpleToken); setResult(RESULT_OK, data); finish(); }); } class ReligionAdapter extends EasyAdapter { final Object[][] choices = { {null, R.string.sync_login_survey_religion_select_one}, {"christianity", R.string.sync_login_survey_religion_christianity}, {"christianity.protestant", R.string.sync_login_survey_religion_christianity_protestant}, {"christianity.lutheran", R.string.sync_login_survey_religion_christianity_lutheran}, {"christianity.methodist", R.string.sync_login_survey_religion_christianity_methodist}, {"christianity.anglican", R.string.sync_login_survey_religion_christianity_anglican}, {"christianity.adventist", R.string.sync_login_survey_religion_christianity_adventist}, {"christianity.pentecostal", R.string.sync_login_survey_religion_christianity_pentecostal}, {"christianity.roman", R.string.sync_login_survey_religion_christianity_roman}, {"christianity.other", R.string.sync_login_survey_religion_christianity_other}, {"islam", R.string.sync_login_survey_religion_islam}, {"buddha", R.string.sync_login_survey_religion_buddha}, {"hindu", R.string.sync_login_survey_religion_hindu}, {"other", R.string.sync_login_survey_religion_other}, {"atheist", R.string.sync_login_survey_religion_atheist}, {"agnostic", R.string.sync_login_survey_religion_agnostic}, }; @Override public String getItem(final int position) { // used by getSelectedItem return (String) choices[position][0]; } @Override public View newView(final int position, final ViewGroup parent) { return getLayoutInflater().inflate(android.R.layout.simple_spinner_item, parent, false); } @Override public View newDropDownView(final int position, final ViewGroup parent) { return getLayoutInflater().inflate(android.R.layout.simple_spinner_dropdown_item, parent, false); } @Override public void bindView(final View view, final int position, final ViewGroup parent) { final TextView text = (TextView) view; text.setText(getString((int) choices[position][1])); } @Override public int getCount() { return choices.length; } } }