/*
* VITacademics
* Copyright (C) 2015 Aneesh Neelam <neelam.aneesh@gmail.com>
* Copyright (C) 2015 Saurabh Joshi <saurabhjoshi94@outlook.com>
* Copyright (C) 2015 Gaurav Agerwala <gauravagerwala@gmail.com>
* Copyright (C) 2015 Karthik Balakrishnan <karthikb351@gmail.com>
* Copyright (C) 2015 Pulkit Juneja <pulkit.16296@gmail.com>
* Copyright (C) 2015 Hemant Jain <hemanham@gmail.com>
* Copyright (C) 2015 Darshan Mehta <darshanmehta17@gmail.com>
*
* This file is part of VITacademics.
*
* VITacademics is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VITacademics is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VITacademics. If not, see <http://www.gnu.org/licenses/>.
*/
package com.karthikb351.vitinfo2.activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.KeyEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.avast.android.dialogs.fragment.DatePickerDialogFragment;
import com.avast.android.dialogs.iface.IDateDialogListener;
import com.karthikb351.vitinfo2.MainApplication;
import com.karthikb351.vitinfo2.R;
import com.karthikb351.vitinfo2.api.NetworkController;
import com.karthikb351.vitinfo2.api.RequestConfig;
import com.karthikb351.vitinfo2.api.ResetTask;
import com.karthikb351.vitinfo2.model.Status;
import com.karthikb351.vitinfo2.utility.Constants;
import com.karthikb351.vitinfo2.utility.NetworkUtils;
import com.karthikb351.vitinfo2.utility.ResultListener;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper;
public class LoginActivity extends AppCompatActivity implements View.OnClickListener, View.OnFocusChangeListener, IDateDialogListener, RadioGroup.OnCheckedChangeListener {
private Toolbar toolbar;
private Button loginButton;
private Button exitButton;
private EditText etRegNo;
private EditText etDOB;
private EditText etPhone;
private TextInputLayout etRegNoHolder;
private TextInputLayout etDOBHolder;
private TextInputLayout etPhoneHolder;
private ProgressBar progressBar;
private RelativeLayout loginLayout;
private LinearLayout loginDetailP1;
private LinearLayout loginDetailP2;
private String campus;
private String registrationNumber;
private String dateOfBirth;
private String mobileNumber;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initialize();
}
/**
* Checks if the user has already logged in or not and accordingly calls animation on the toolbar.
*
* @see #collapseView(View)
*/
@Override
protected void onPostResume() {
super.onPostResume();
// Used to set the inner left padding of toolbar to zero to let the image view be placed at center exactly.
toolbar.setContentInsetsAbsolute(0, 0);
toolbar.requestLayout();
final boolean isLoggedIn = loginCheck();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (isLoggedIn) {
((MainApplication) getApplication()).getDataHolderInstance().refreshData(LoginActivity.this, new ResultListener() {
@Override
public void onSuccess() {
startActivity(new Intent(LoginActivity.this, MainActivity.class));
}
@Override
public void onFailure(Status status) {
Toast.makeText(LoginActivity.this, status.getMessage(), Toast.LENGTH_SHORT).show();
new ResetTask(LoginActivity.this).execute();
startActivity(new Intent(LoginActivity.this, LoginActivity.class));
}
});
} else {
collapseView(toolbar);
}
}
}, 800);
}
/**
* Animates the view by scaling it from MATCH_PARENT to WRAP_CONTENT.
*
* @param view - View to be collapsed
*/
private void collapseView(final View view) {
Rect rect = new Rect();
view.getGlobalVisibleRect(rect);
final int initialHeight = rect.bottom - rect.top;
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
final int targetHeight = view.getMeasuredHeight();
Animation animation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if (interpolatedTime == 1) {
view.getLayoutParams().height = targetHeight;
} else {
view.getLayoutParams().height = targetHeight + (int) ((initialHeight - targetHeight) * (1 - interpolatedTime));
view.requestLayout();
}
}
@Override
public boolean willChangeBounds() {
return true;
}
};
int difference = initialHeight - targetHeight;
if (difference < 0){
difference = 0;
}
animation.setDuration((int) (difference / view.getContext().getResources().getDisplayMetrics().density));
view.startAnimation(animation);
}
/**
* Initializes all the variables and objects of this class.
*/
private void initialize() {
toolbar = (Toolbar) findViewById(R.id.toolbarLogin);
setSupportActionBar(toolbar);
loginButton = (Button) findViewById(R.id.loginButton);
loginButton.setOnClickListener(this);
exitButton = (Button) findViewById(R.id.exitButton);
exitButton.setOnClickListener(this);
etRegNo = (EditText) findViewById(R.id.etRegNo);
etDOB = (EditText) findViewById(R.id.etDOB);
etPhone = (EditText) findViewById(R.id.etPhone);
etDOB.setOnFocusChangeListener(this);
etDOB.setOnClickListener(this);
etRegNoHolder = (TextInputLayout) findViewById(R.id.etRegNoHolder);
etDOBHolder = (TextInputLayout) findViewById(R.id.etDOBHolder);
etPhoneHolder = (TextInputLayout) findViewById(R.id.etPhoneHolder);
loginLayout = (RelativeLayout) findViewById(R.id.rlLoginDetails);
progressBar = (ProgressBar) findViewById(R.id.progressBarLogin);
loginDetailP1 = (LinearLayout) findViewById(R.id.llLoginDetailsP1);
loginDetailP2 = (LinearLayout) findViewById(R.id.llLoginDetailsP2);
RadioGroup radioGroupCampus = (RadioGroup) findViewById(R.id.select_campus);
radioGroupCampus.setOnCheckedChangeListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.loginButton:
if (loginDetailP1.getVisibility() == View.VISIBLE) {
switchToFormTwo();
} else {
validateForm();
}
break;
case R.id.exitButton:
if (loginDetailP2.getVisibility() == View.VISIBLE) {
switchToFormOne();
} else {
finish();
}
break;
case R.id.etDOB:
launchDatePicker();
break;
}
}
/**
* Hides the login form and makes campus choice radio buttons visible
*/
private void switchToFormOne() {
loginDetailP1.setVisibility(View.VISIBLE);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.slide_in_left);
Animation animation1 = AnimationUtils.loadAnimation(this, R.anim.slide_out_right);
loginDetailP2.setAnimation(animation1);
loginDetailP2.animate();
loginDetailP1.setAnimation(animation);
loginDetailP1.animate();
loginButton.setText(getResources().getString(R.string.button_next));
loginDetailP2.setVisibility(View.GONE);
}
/**
* Hides the campus choice radio buttons and makes the login form visible
*/
private void switchToFormTwo() {
loginDetailP2.setVisibility(View.VISIBLE);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.slide_out_left);
Animation animation1 = AnimationUtils.loadAnimation(this, R.anim.slide_in_right);
loginDetailP2.setAnimation(animation1);
loginDetailP2.animate();
loginDetailP1.setAnimation(animation);
loginDetailP1.animate();
loginButton.setText(getResources().getString(R.string.button_login));
loginDetailP1.setVisibility(View.GONE);
}
/**
* Validates the sign in form and shows appropriate error for incomplete and invalid input
*/
private void validateForm() {
registrationNumber = etRegNo.getText().toString().trim().toUpperCase();
dateOfBirth = etDOB.getText().toString().trim();
mobileNumber = etPhone.getText().toString().trim();
etRegNoHolder.setError(null);
etDOBHolder.setError(null);
etPhoneHolder.setError(null);
if (registrationNumber.isEmpty()) {
etRegNoHolder.setError("Enter a valid registration number");
setFocusTo(etRegNo, etDOB, etPhone);
} else if (!isValidRegNo(registrationNumber)) {
etRegNoHolder.setError("Enter a valid registration number");
setFocusTo(etRegNo, etDOB, etPhone);
} else if (dateOfBirth.isEmpty()) {
etDOBHolder.setError("Choose a valid date");
setFocusTo(etDOB, etRegNo, etPhone);
} else if ((mobileNumber.isEmpty()) && campus.contentEquals(Constants.CAMPUS_VELLORE)) {
etPhoneHolder.setError("Enter a valid phone number");
setFocusTo(etPhone, etDOB, etRegNo);
} else {
if (NetworkUtils.isNetworkConnected(this)) {
showForm(false);
loginToServer();
} else {
launchNetworkError();
}
}
}
/**
* Authenticates credentials entered in the form with the server and fetches data
*/
private void loginToServer() {
NetworkController networkController = NetworkController.getInstance(this, campus, registrationNumber, dateOfBirth, mobileNumber);
final ResultListener resultListener = new ResultListener() {
@Override
public void onSuccess() {
startActivity(new Intent(LoginActivity.this, MainActivity.class));
}
@Override
public void onFailure(Status status) {
try {
Snackbar.make(findViewById(R.id.rlLoginLayout), status.getMessage(), Snackbar.LENGTH_LONG).show();
showForm(true);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
@Override
public void onProgress() {
}
};
RequestConfig requestConfig = new RequestConfig(new ResultListener() {
@Override
public void onSuccess() {
try {
((MainApplication) LoginActivity.this.getApplication()).getDataHolderInstance().refreshData(LoginActivity.this, resultListener);
} catch (NullPointerException ignore) {
}
}
@Override
public void onFailure(Status status) {
resultListener.onFailure(status);
}
@Override
public void onProgress() {
}
});
requestConfig.addRequest(RequestConfig.REQUEST_SYSTEM);
requestConfig.addRequest(RequestConfig.REQUEST_REFRESH);
requestConfig.addRequest(RequestConfig.REQUEST_GRADES);
requestConfig.addRequest(RequestConfig.REQUEST_TOKEN);
networkController.dispatch(requestConfig);
}
/**
* Checks if the entered registration number is valid
*
* @param registrationNumber - The number to be validated
* @return true if valid, false otherwise
*/
private boolean isValidRegNo(String registrationNumber) {
if (registrationNumber.length() > 5) {
String patternAlnum = "^[A-Z0-9]*$";
String patternNum = "^[0-9]*$";
if (registrationNumber.matches(patternAlnum) && registrationNumber.substring(0, 2).matches(patternNum)) {
Calendar calendar = Calendar.getInstance();
String year = calendar.get(Calendar.YEAR) + "";
year = year.substring(2);
int iyear = Integer.parseInt(year);
String yearReg = registrationNumber.substring(0, 2);
int iyearReg = Integer.parseInt(yearReg);
if (iyearReg <= iyear) {
return true;
}
}
}
return false;
}
/**
* Toggles the visibility of the login form
*
* @param isVisible true if form is to be made visible
*/
private void showForm(boolean isVisible) {
loginButton.setEnabled(isVisible);
exitButton.setEnabled(isVisible);
if (isVisible) {
loginLayout.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
} else {
loginLayout.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
}
}
/**
* Launches a SnackBar which notifies the user that there is no active internet connection
*/
private void launchNetworkError() {
Snackbar.make(findViewById(R.id.rlLoginLayout), "No Internet Connection", Snackbar.LENGTH_LONG)
.setAction("RETRY", new View.OnClickListener() {
@Override
public void onClick(View v) {
validateForm();
}
}).show();
}
/**
* Switches the focus of the edit text
*
* @param toFocusOn view to be brought into focus
* @param toRemoveFocusFrom1 view to be cleared from user's focus
* @param toRemoveFocusFrom2 view to be cleared from user's focus
*/
private void setFocusTo(EditText toFocusOn, EditText toRemoveFocusFrom1, EditText toRemoveFocusFrom2) {
toRemoveFocusFrom1.clearFocus();
toRemoveFocusFrom2.clearFocus();
toFocusOn.requestFocus();
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
launchDatePicker();
}
}
/**
* Launches the Date Picker
*/
private void launchDatePicker() {
DatePickerDialogFragment
.createBuilder(this, getSupportFragmentManager())
.setDate(new Date())
.setPositiveButtonText(android.R.string.ok)
.setNegativeButtonText(android.R.string.cancel)
.setRequestCode(24)
.show();
}
@Override
public void onPositiveButtonClicked(int i, Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
SimpleDateFormat sdf = new SimpleDateFormat(Constants.API_DATEOFBIRTH_FORMAT, Locale.US);
etDOB.setText(sdf.format(calendar.getTime()));
}
@Override
public void onNegativeButtonClicked(int i, Date date) {
}
/**
* Checks the shared preferences if the user has already logged in
*
* @return true is logged in already, false otherwise
*/
private boolean loginCheck() {
SharedPreferences sharedPreferences = getSharedPreferences(Constants.FILENAME_SHAREDPREFERENCES, Context.MODE_PRIVATE);
String campus = sharedPreferences.getString(Constants.KEY_CAMPUS, null);
String registerNumber = sharedPreferences.getString(Constants.KEY_REGISTERNUMBER, null);
String dateOfBirth = sharedPreferences.getString(Constants.KEY_DATEOFBIRTH, null);
String mobileNumber = sharedPreferences.getString(Constants.KEY_MOBILE, null);
return (Constants.CAMPUS_VELLORE.equals(campus) && registerNumber != null && dateOfBirth != null && mobileNumber != null) || (Constants.CAMPUS_CHENNAI.equals(campus) && registerNumber != null && dateOfBirth != null);
}
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
loginButton.setEnabled(true);
switch (checkedId) {
case R.id.select_vellore:
campus = Constants.CAMPUS_VELLORE;
etPhoneHolder.setVisibility(View.VISIBLE);
break;
case R.id.select_chennai:
campus = Constants.CAMPUS_CHENNAI;
etPhoneHolder.setVisibility(View.GONE);
break;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (loginDetailP2.getVisibility() == View.VISIBLE) {
switchToFormOne();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
}