package kc.spark.pixels.android.ui; import static org.solemnsilence.util.Py.list; import static org.solemnsilence.util.Py.truthy; import kc.get.pixel.list.android.R; import kc.spark.pixels.android.cloud.ApiFacade; import kc.spark.pixels.android.cloud.requestservice.SimpleSparkApiService; import kc.spark.pixels.android.ui.corelist.CoreListActivity; import kc.spark.pixels.android.ui.util.Ui; import kc.spark.pixels.android.util.NetConnectionHelper; import org.apache.http.HttpStatus; import org.solemnsilence.util.EZ; import org.solemnsilence.util.TLog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.text.TextUtils; import android.util.Patterns; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.EditText; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; public class LoginActivity extends BaseActivity { // UI references. private EditText mEmailView; private EditText mPasswordView; private Button accountAction; private String email; private String password; private NetConnectionHelper netConnectionHelper; private LoggedInReceiver loginReceiver = new LoggedInReceiver(); private DevicesLoadedReceiver devicesLoadedReceiver = new DevicesLoadedReceiver(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_log_in); mEmailView = Ui.findView(this, R.id.email); mPasswordView = Ui.findView(this, R.id.password); mEmailView.setText(prefs.getUsername()); netConnectionHelper = new NetConnectionHelper(this); mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) { if (id == R.id.login || id == EditorInfo.IME_NULL) { attemptLogin(); return true; } return false; } }); accountAction = Ui.findView(this, R.id.sign_up_button); accountAction.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { attemptLogin(); } }); // set up touch listeners on form fields, to auto scroll when the // keyboard pops up for (View view : list(mEmailView, mPasswordView)) { view.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { scrollAccountForm(); } return false; } }); } TextView noAccountYet = Ui.setTextFromHtml(this, R.id.no_account_yet, R.string.i_dont_have_an_account); noAccountYet.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { launchSignUpActivity(); } }); TextView forgotPassword = Ui.setTextFromHtml(this, R.id.forgot_password, R.string.action_forgot_password); forgotPassword.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { openUri(R.string.uri_forgot_password); } }); } @Override protected void onStart() { super.onStart(); broadcastMgr.registerReceiver(loginReceiver, loginReceiver.getFilter()); } @Override protected void onStop() { broadcastMgr.unregisterReceiver(devicesLoadedReceiver); broadcastMgr.unregisterReceiver(loginReceiver); super.onStop(); } private void scrollAccountForm() { // delay this until after the keyboard has popped up so the scroll view // is actually able to scroll Runnable scrollRunnable = new Runnable() { @Override public void run() { ScrollView scrollArea = Ui.findView(LoginActivity.this, R.id.scroll_area); // using fullScroll() or pageScroll() impacts which child widget // gets focus, so that doesn't work here, instead just scroll by // an absurdly large number. scrollArea.scrollBy(0, 5000); } }; // Doing this twice because sometimes it takes a moment for the keyboard // to pop up, changing the screen dimensions and allowing scrolling EZ.runOnMainThreadDelayed(scrollRunnable, 150); EZ.runOnMainThreadDelayed(scrollRunnable, 750); } /** * Attempts to sign in or register the account specified by the login form. * If there are form errors (invalid email, missing fields, etc.), the * errors are presented and no actual login attempt is made. */ public void attemptLogin() { // Reset errors. mEmailView.setError(null); mPasswordView.setError(null); // Store values at the time of the login attempt. email = mEmailView.getText().toString(); password = mPasswordView.getText().toString(); boolean cancel = false; View focusView = null; // Check for a valid email address. if (!truthy(email)) { mEmailView.setError(getString(R.string.error_field_required)); focusView = mEmailView; cancel = true; } else if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) { mEmailView.setError(getString(R.string.error_invalid_email)); focusView = mEmailView; cancel = true; } // Check for a valid password. if (TextUtils.isEmpty(password)) { mPasswordView.setError(getString(R.string.error_field_required)); focusView = mPasswordView; cancel = true; } else if (password.length() < 4) { mPasswordView.setError(getString(R.string.error_invalid_password)); focusView = mPasswordView; cancel = true; } if (cancel) { // There was an error; don't attempt login and focus the first // form field with an error. focusView.requestFocus(); } else { // Show a progress spinner, and kick off a background task to // perform the user login attempt. showProgress(true); api.logIn(email, password); } } private void showProgress(boolean show) { super.showProgress(R.id.progress_indicator, show); accountAction.setEnabled(!show); } private void onLogInComplete(boolean success, int statusCode, String error) { if (success) { broadcastMgr.registerReceiver(devicesLoadedReceiver, devicesLoadedReceiver.getFilter()); api.requestAllDevices(); Toast toast = Toast.makeText(this, "Loading your Cores...", Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); } else { showProgress(false); if (!netConnectionHelper.isConnectedViaWifi()) { getErrorsDelegate().showCloudUnreachableDialog(); } else if (statusCode == 400) { mPasswordView.setError(getString(R.string.error_incorrect_password)); mPasswordView.requestFocus(); } else { getErrorsDelegate().showHttpErrorDialog(statusCode); } } } private void onDevicesUpdated(boolean success, String error) { showProgress(false); if (!isFinishing()) { startActivity(new Intent(this, CoreListActivity.class) .putExtra(CoreListActivity.ARG_ENTERING_FROM_LAUNCH, true)); } finish(); } void launchSignUpActivity() { // the value here doesn't really matter, it's just a flag. startActivity(new Intent(this, SignUpActivity.class) .putExtra(SignUpActivity.EXTRA_FROM_LOGIN, "")); finish(); } class DevicesLoadedReceiver extends BroadcastReceiver { public IntentFilter getFilter() { return new IntentFilter(ApiFacade.BROADCAST_DEVICES_UPDATED); } @Override public void onReceive(Context context, Intent intent) { onDevicesUpdated((ApiFacade.getResultCode(intent) == HttpStatus.SC_OK), intent.getStringExtra(SimpleSparkApiService.EXTRA_ERROR_MSG)); } } class LoggedInReceiver extends BroadcastReceiver { public IntentFilter getFilter() { return new IntentFilter(ApiFacade.BROADCAST_LOG_IN_FINISHED); } @Override public void onReceive(Context context, Intent intent) { onLogInComplete((ApiFacade.getResultCode(intent) == HttpStatus.SC_OK), ApiFacade.getResultCode(intent), intent.getStringExtra(SimpleSparkApiService.EXTRA_ERROR_MSG)); } } static final TLog log = new TLog(LoginActivity.class); }