Java tutorial
/* * Copyright 2013 i'm SpA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package it.imwatch.nfclottery.dialogs; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.util.Patterns; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.TranslateAnimation; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import de.keyboardsurfer.android.widget.crouton.Style; import it.imwatch.nfclottery.DataHelper; import it.imwatch.nfclottery.MainActivity; import it.imwatch.nfclottery.R; import java.util.ArrayList; import java.util.regex.Pattern; import static it.imwatch.nfclottery.Const.DEBUG; /** * A dialog that allows the user to manually add a contact to the database. */ public class InsertContactDialog extends DialogFragment { private static final String TAG = InsertContactDialog.class.getSimpleName(); private static final Pattern NAME_PATTERN = Pattern.compile("^\\p{L}+\\s+(?:\\p{L}+\\s*)+", Pattern.CASE_INSENSITIVE); private static final String EXTRA_NAME_ERROR = "name_error", EXTRA_EMAIL_ERROR = "email_error"; private float mErrorAnimTranslateY; private TextView mEmailErrorTextView, mNameErrorTextView; private int mNameErrorState = 1, mEmailErrorState = 1; private View.OnFocusChangeListener mFocusWatcher = new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { final CharSequence text = ((TextView) v).getText(); final Context context = v.getContext(); if (v.getId() == R.id.txt_edit_email) { validateEmailInput(text, context); } else if (v.getId() == R.id.txt_edit_name) { validateNameInput(text); } } } }; private TextWatcher mEmailTypingWatcher = 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) { final CharSequence text = s.toString(); final Context context = InsertContactDialog.this.getActivity(); if (context != null) { validateEmailInput(text, context); } } }; private EditText mEmailEditText, mNameEditText, mOrganizationEditText, mTitleEditText;; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // Use the Builder class for convenient dialog construction final Activity activity = getActivity(); if (activity == null) { Log.e(TAG, "Not attached to Activity: cannot build dialog"); return null; } AlertDialog.Builder builder = new AlertDialog.Builder(activity); // Get the layout inflater LayoutInflater inflater = LayoutInflater.from(activity); final View rootView = inflater.inflate(R.layout.dialog_insert, null); if (rootView == null) { Log.e(TAG, "Cannot inflate the dialog layout!"); return null; } mErrorAnimTranslateY = getResources().getDimensionPixelSize(R.dimen.error_anim_translate_y); mEmailErrorTextView = (TextView) rootView.findViewById(R.id.lbl_email_error); mNameErrorTextView = (TextView) rootView.findViewById(R.id.lbl_name_error); // Restore instance state (if any) if (savedInstanceState != null) { mNameErrorState = savedInstanceState.getInt(EXTRA_NAME_ERROR, 0); mEmailErrorState = savedInstanceState.getInt(EXTRA_EMAIL_ERROR, 0); if (mNameErrorState == 1) showNameError(); if (mEmailErrorState == 1) { showEmailError(activity.getString(R.string.error_emailinput_invalid), 1); } else if (mEmailErrorState == 2) { showEmailError(activity.getString(R.string.error_emailinput_duplicate), 2); } } mEmailEditText = (EditText) rootView.findViewById(R.id.txt_edit_email); mNameEditText = (EditText) rootView.findViewById(R.id.txt_edit_name); mOrganizationEditText = (EditText) rootView.findViewById(R.id.txt_edit_organization); mTitleEditText = (EditText) rootView.findViewById(R.id.txt_edit_title); // Add the check for a valid email address and names mEmailEditText.setOnFocusChangeListener(mFocusWatcher); mNameEditText.setOnFocusChangeListener(mFocusWatcher); // Add the check for a valid email during typing mEmailEditText.addTextChangedListener(mEmailTypingWatcher); // Inflate and set the layout for the dialog // Pass null as the parent view because its going in the dialog layout builder.setView(rootView).setPositiveButton(android.R.string.ok, null) .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { final Dialog thisDialog = InsertContactDialog.this.getDialog(); if (thisDialog != null) { thisDialog.cancel(); } else { Log.w(TAG, "Can't get the Dialog instance."); } } }); // Create the AlertDialog object and return it AlertDialog alertDialog = builder.create(); alertDialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { final AlertDialog alertDialog = (AlertDialog) dialog; // Disable the positive button. It will be enabled only when there is a valid email final Button button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); if (button != null) { button.setEnabled(false); button.setOnClickListener(new DontAutoCloseDialogListener(alertDialog)); } else { Log.w(TAG, "Can't get the dialog positive button."); } alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); } }); return alertDialog; } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(EXTRA_NAME_ERROR, mNameErrorState); outState.putInt(EXTRA_EMAIL_ERROR, mEmailErrorState); } /** * Check the data inserted into the form and it all the required fields are present, * then it adds the contact into DB */ private boolean checkAndInsert() { final Activity activity = getActivity(); if (activity == null) { Log.e(TAG, "Not attached to Activity: cannot insert contact in DB"); return true; // We can close, there's nothing to do anyway } String email = null; ArrayList<String> name = new ArrayList<String>(1), organization = new ArrayList<String>(1), title = new ArrayList<String>(1); if (mNameEditText != null && mNameEditText.getText() != null) { name.add(mNameEditText.getText().toString()); } if (mEmailEditText != null && mEmailEditText.getText() != null) { email = mEmailEditText.getText().toString(); } if (mOrganizationEditText != null && mOrganizationEditText.getText() != null && TextUtils.isGraphic(mOrganizationEditText.getText())) { organization.add(mOrganizationEditText.getText().toString()); } if (mTitleEditText != null && mTitleEditText.getText() != null && TextUtils.isGraphic(mTitleEditText.getText())) { title.add(mTitleEditText.getText().toString()); } if (activity instanceof MainActivity) { final MainActivity mainActivity = (MainActivity) activity; if (!isValidEmailAddress(email)) { // Empty or invalid email field! showEmailError(activity.getString(R.string.error_emailinput_invalid), 1); return false; } if (DataHelper.isEmailAlreadyPresent(mainActivity, email)) { // We add each email only once showEmailError(activity.getString(R.string.error_emailinput_duplicate), 2); return false; } if (DataHelper.insertContact(mainActivity, name, email, organization, title)) { mainActivity.showCroutonNao(activity.getString(R.string.new_contact_added, email), Style.CONFIRM); mainActivity.updateParticipantsCount(); return true; } return false; } else { Log.e(TAG, "The parent Activity is not MainActivity! Wat is this I don't even"); if (DEBUG) Log.d(TAG, "Activity class: " + activity.getLocalClassName()); Toast.makeText(activity, activity.getString(R.string.insert_failed_wrong_parent), Toast.LENGTH_SHORT) .show(); return true; // We can close, there's nothing to do anyway } } /** * Validates a string as an email address. * * @param email The email address to validate * * @return Returns true if the string is a valid email address, * false otherwise */ private static boolean isValidEmailAddress(CharSequence email) { return email != null && Patterns.EMAIL_ADDRESS.matcher(email.toString()).matches(); } /** * Validates a string as a name. * * @param name The name to validate * * @return Returns true if the string is a valid name, * false otherwise */ private static boolean isValidName(CharSequence name) { return name != null && NAME_PATTERN.matcher(name.toString()).matches(); } /** * Sets the validation state of the form. * * @param validated When true, the confirmation button will be enabled; * when false, it will be disabled. */ private void setFormIsValidated(boolean validated) { final AlertDialog dialog = (AlertDialog) getDialog(); if (dialog != null) { final Button button = dialog.getButton(DialogInterface.BUTTON_POSITIVE); if (button != null) { button.setEnabled(validated); } } } /** * Validates the provided text as an email input from the user. * * @param text The text to validate as email * @param context The current context */ private void validateEmailInput(CharSequence text, Context context) { if (context != null) { if (!isValidEmailAddress(text)) { showEmailError(context.getString(R.string.error_emailinput_invalid), 1); } else if (DataHelper.isEmailAlreadyPresent(context, text.toString())) { showEmailError(context.getString(R.string.error_emailinput_duplicate), 2); } else { hideEmailError(); } } else { hideEmailError(); } } /** * Validates the provided text as a name input from the user. * * @param text The text to validate as name */ private void validateNameInput(CharSequence text) { if (!isValidName(text)) { showNameError(); } else { hideNameError(); } } /** * Hides the email error textview. */ private void hideEmailError() { mEmailErrorState = 0; // Re-enable the positive button of the dialog iif the name is also valid setFormIsValidated(mNameErrorState == 0); if (mEmailErrorTextView.getVisibility() == View.GONE) { return; // No need to animate out the textview, it's already gone } AnimationSet fadeOutSet = new AnimationSet(true); fadeOutSet.addAnimation(new AlphaAnimation(1f, 0f)); fadeOutSet.addAnimation(new TranslateAnimation(0f, 0f, 0f, -mErrorAnimTranslateY)); fadeOutSet.setDuration(300); fadeOutSet.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { // Don't care } @Override public void onAnimationEnd(Animation animation) { mEmailErrorTextView.setVisibility(View.GONE); } @Override public void onAnimationRepeat(Animation animation) { // Don't care } }); mEmailErrorTextView.startAnimation(fadeOutSet); } /** * Hides the name error textview. */ private void hideNameError() { mNameErrorState = 0; // Re-enable the positive button of the dialog iif the name is also valid setFormIsValidated(mEmailErrorState == 0); if (mNameErrorTextView.getVisibility() == View.GONE) { return; // No need to animate out the textview, it's already gone } AnimationSet fadeOutSet = new AnimationSet(true); fadeOutSet.addAnimation(new AlphaAnimation(1f, 0f)); fadeOutSet.addAnimation(new TranslateAnimation(0f, 0f, 0f, -mErrorAnimTranslateY)); fadeOutSet.setDuration(300); fadeOutSet.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { // Don't care } @Override public void onAnimationEnd(Animation animation) { mNameErrorTextView.setVisibility(View.GONE); } @Override public void onAnimationRepeat(Animation animation) { // Don't care } }); mNameErrorTextView.startAnimation(fadeOutSet); } /** * Shows the email error textfield with the appropriate * error message. * * @param message The error message to show */ private void showEmailError(CharSequence message, int errState) { mEmailErrorTextView.setText(message); mEmailErrorState = errState; // Disable the positive button of the dialog setFormIsValidated(false); if (mEmailErrorTextView.getVisibility() == View.VISIBLE) { return; // No need to animate in the textview, it's already visible } mEmailErrorTextView.setVisibility(View.VISIBLE); AnimationSet fadeInSet = new AnimationSet(true); fadeInSet.addAnimation(new AlphaAnimation(0f, 1f)); fadeInSet.addAnimation(new TranslateAnimation(0f, 0f, -mErrorAnimTranslateY, 0f)); fadeInSet.setDuration(300); mEmailErrorTextView.startAnimation(fadeInSet); } /** * Shows the name error textfield with the appropriate * error message. */ private void showNameError() { mNameErrorState = 1; // Disable the positive button of the dialog setFormIsValidated(false); if (mNameErrorTextView.getVisibility() == View.VISIBLE) { return; // No need to animate in the textview, it's already visible } mNameErrorTextView.setVisibility(View.VISIBLE); AnimationSet fadeInSet = new AnimationSet(true); fadeInSet.addAnimation(new AlphaAnimation(0f, 1f)); fadeInSet.addAnimation(new TranslateAnimation(0f, 0f, -mErrorAnimTranslateY, 0f)); fadeInSet.setDuration(300); mNameErrorTextView.startAnimation(fadeInSet); } private class DontAutoCloseDialogListener implements View.OnClickListener { private final AlertDialog mDialog; private DontAutoCloseDialogListener(AlertDialog dialog) { mDialog = dialog; } @Override public void onClick(View v) { validateEmailInput(mEmailEditText.getText(), mDialog.getContext()); validateNameInput(mNameEditText.getText()); final Button button = mDialog.getButton(AlertDialog.BUTTON_POSITIVE); if (button != null && button.isEnabled()) { // Only proceed if the form is validated if (checkAndInsert()) { mDialog.dismiss(); } } } } }