/*
* Copyright (C) 2016 Payworks GmbH (http://www.payworks.com)
*
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package io.mpos.ui.acquirer.view;
import android.app.Activity;
import android.app.Fragment;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
import io.mpos.Mpos;
import io.mpos.accounts.listeners.LoginListener;
import io.mpos.accounts.listeners.PasswordResetRequestListener;
import io.mpos.errors.ErrorType;
import io.mpos.errors.MposError;
import io.mpos.provider.ProviderMode;
import io.mpos.ui.R;
import io.mpos.ui.acquirer.MposUiAccountManager;
import io.mpos.ui.shared.MposUi;
import io.mpos.ui.shared.util.UiHelper;
public class LoginFragment extends Fragment {
public static final String TAG = "LoginFragment";
public interface Interaction {
void onLoginCompleted();
void onLoginModeChanged(boolean loginMode);
}
private Interaction mInteractionActivity;
private String mApplicationIdentifier;
private ImageView mLogoImageView;
private EditText mEmailEditText;
private EditText mPasswordEditText;
private Button mActionButton;
private Button mForgotPasswordButton;
private ProgressBar mProgressBar;
private String mEmailText;
private String mPasswordText;
private boolean loginMode = true;
private MposUiAccountManager mMposUiAccountManager;
public static LoginFragment newInstance(String applicationIdentifier) {
LoginFragment fragment = new LoginFragment();
fragment.setApplicationIdentifier(applicationIdentifier);
return fragment;
}
public LoginFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mMposUiAccountManager = MposUiAccountManager.getInitializedInstance();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.mpu_fragment_login, container, false);
mEmailEditText = (EditText) rootView.findViewById(R.id.mpu_email_view);
mPasswordEditText = (EditText) rootView.findViewById(R.id.mpu_password_view);
mActionButton = (Button) rootView.findViewById(R.id.mpu_action_button);
mForgotPasswordButton = (Button) rootView.findViewById(R.id.mpu_forgot_password_button);
mProgressBar = (ProgressBar) rootView.findViewById(R.id.mpu_login_progress);
mLogoImageView = (ImageView) rootView.findViewById(R.id.mpu_logo_image);
setupUI();
mForgotPasswordButton.setOnClickListener(mForgotPasswordClickListener);
mActionButton.setOnClickListener(mActionButtonClickListener);
mEmailEditText.addTextChangedListener(mEmailTextWatcher);
mPasswordEditText.addTextChangedListener(mPasswordTextWatcher);
return rootView;
}
@Override
public void onResume() {
super.onResume();
getActivity().setTitle(R.string.MPULogin);
}
public void setLoginMode(boolean login) {
if (login) {
loginMode = true;
mActionButton.setEnabled(false);
mPasswordEditText.setText(null);
mPasswordEditText.setVisibility(View.VISIBLE);
mForgotPasswordButton.setText(R.string.MPUForgot);
mActionButton.setText(R.string.MPULogin);
} else {
loginMode = false;
mPasswordEditText.setVisibility(View.GONE);
mForgotPasswordButton.setText(R.string.MPUBack);
mActionButton.setText(R.string.MPURequestPassword);
}
mInteractionActivity.onLoginModeChanged(login);
}
public void setApplicationIdentifier(String applicationIdentifier) {
this.mApplicationIdentifier = applicationIdentifier;
}
View.OnClickListener mForgotPasswordClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
evaluateEmailField();
setLoginMode(!loginMode);
}
};
View.OnClickListener mActionButtonClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
mEmailText = mEmailEditText.getText().toString();
mPasswordText = mPasswordEditText.getText().toString();
ProviderMode providerMode = mMposUiAccountManager.getProviderMode();
if (loginMode) {
enableUi(false);
Mpos.loginWithApplication(getActivity().getApplicationContext(), providerMode, mApplicationIdentifier, mEmailText, mPasswordText, new LoginListener() {
@Override
public void onLoginSuccessful(final String username, final String merchantId, final String merchantSecret) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
enableUi(true);
mMposUiAccountManager.loginWithCredentials(getActivity().getApplicationContext(), username, merchantId, merchantSecret);
mInteractionActivity.onLoginCompleted();
}
});
}
@Override
public void onLoginFailure(String s, final MposError mposError) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
enableUi(true);
if (mposError.getErrorType() == ErrorType.SERVER_AUTHENTICATION_FAILED) {
showErrorDialog(getString(R.string.MPUWrongCredentials));
} else {
showErrorDialog(mposError.getInfo());
}
}
});
}
});
} else {
enableUi(false);
Mpos.requestPasswordResetForApplication(getActivity(), providerMode, mApplicationIdentifier, mEmailText, new PasswordResetRequestListener() {
@Override
public void onPasswordResetRequestSuccessful(String username) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
enableUi(true);
Toast.makeText(getActivity(), R.string.MPUPasswordReset, Toast.LENGTH_SHORT).show();
setLoginMode(true);
}
});
}
@Override
public void onPasswordResetRequestFailure(String s, final MposError mposError) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
enableUi(true);
if (mposError.getErrorType() == ErrorType.SERVER_UNKNOWN_USERNAME) {
showErrorDialog(getString(R.string.MPUUnknownUsername));
} else {
showErrorDialog(mposError.getInfo());
}
}
});
}
});
}
}
};
private void showErrorDialog(String message) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setTitle(getString(R.string.MPUError));
alertDialogBuilder.setMessage(message);
alertDialogBuilder.setPositiveButton(getString(R.string.MPUOK), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialogBuilder.create().show();
}
TextWatcher mEmailTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (!loginMode) {
evaluateEmailField();
} else {
if (!TextUtils.isEmpty(mPasswordEditText.getText().toString())) {
if (!isValidEmail(editable.toString())) {
enableAction(false);
} else {
enableAction(true);
}
}
}
}
};
TextWatcher mPasswordTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (editable.length() > 0 && !TextUtils.isEmpty(mEmailEditText.getText().toString())) {
if (isValidEmail(mEmailEditText.getText().toString())) {
enableAction(true);
} else {
mEmailEditText.setError(getResources().getString(R.string.MPUInvalidEmailAddress));
}
} else {
enableAction(false);
}
}
};
private void setupUI() {
UiHelper.tintView(mEmailEditText, MposUi.getInitializedInstance().getConfiguration().getAppearance().getColorPrimary());
UiHelper.tintView(mPasswordEditText, MposUi.getInitializedInstance().getConfiguration().getAppearance().getColorPrimary());
UiHelper.tintButton(mActionButton, MposUi.getInitializedInstance().getConfiguration().getAppearance().getColorPrimary());
mLogoImageView.setImageResource(mMposUiAccountManager.getApplicationData().getImageResourceId());
mEmailEditText.setText(mMposUiAccountManager.getUsername());
}
private void evaluateEmailField() {
// Improving UX
// 1. If empty disable the action button
if (TextUtils.isEmpty(mEmailEditText.getText().toString())) {
enableAction(false);
} else if (!isValidEmail(mEmailEditText.getText().toString())) { //2. If invalid email: show error and disable action button
enableAction(false);
} else { // 3. Seems to be valid email and not empty. Enable action button.
enableAction(true);
}
}
private void enableAction(boolean enable) {
mActionButton.setEnabled(enable);
}
private boolean isValidEmail(CharSequence target) {
return !TextUtils.isEmpty(target) && android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.mpu_menu_login, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
Drawable drawable = menu.findItem(R.id.mpu_action_help).getIcon();
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable, MposUi.getInitializedInstance().getConfiguration().getAppearance().getTextColorPrimary());
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.mpu_action_help) {
// Take me away from the app!
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(mMposUiAccountManager.getApplicationData().getHelpUrl()));
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
private void enableUi(boolean enabled) {
mEmailEditText.setEnabled(enabled);
mPasswordEditText.setEnabled(enabled);
mActionButton.setEnabled(enabled);
mForgotPasswordButton.setEnabled(enabled);
if (enabled) {
mProgressBar.setVisibility(View.GONE);
} else {
mProgressBar.setVisibility(View.VISIBLE);
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
activity.setTitle(R.string.MPUPrinting);
mInteractionActivity = (Interaction) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement LoginFragment.Interaction");
}
}
@Override
public void onDetach() {
super.onDetach();
mInteractionActivity = null;
}
}