/*
* The contents of this file are subject to the OpenMRS Public License
* Version 1.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://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.mobile.activities.login;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.AppCompatImageView;
import android.text.InputType;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import org.openmrs.mobile.R;
import org.openmrs.mobile.activities.ACBaseFragment;
import org.openmrs.mobile.activities.dashboard.DashboardActivity;
import org.openmrs.mobile.activities.dialog.CustomFragmentDialog;
import org.openmrs.mobile.api.FormListService;
import org.openmrs.mobile.application.OpenMRS;
import org.openmrs.mobile.bundle.CustomDialogBundle;
import org.openmrs.mobile.listeners.watcher.LoginValidatorWatcher;
import org.openmrs.mobile.models.Location;
import org.openmrs.mobile.utilities.ApplicationConstants;
import org.openmrs.mobile.utilities.FontsUtil;
import org.openmrs.mobile.utilities.ImageUtils;
import org.openmrs.mobile.utilities.StringUtils;
import org.openmrs.mobile.utilities.ToastUtil;
import org.openmrs.mobile.utilities.URLValidator;
import java.util.ArrayList;
import java.util.List;
public class LoginFragment extends ACBaseFragment<LoginContract.Presenter> implements LoginContract.View {
private View mRootView;
private TextView mForgotPass;
private EditText mUrl;
private EditText mUsername;
private EditText mPassword;
private CheckBox mShowPassword;
private Button mLoginButton;
private ProgressBar mSpinner;
private Spinner mDropdownLocation;
private LinearLayout mLoginFormView;
private AppCompatImageView mLoginSyncButton;
private TextView mSyncStateLabel;
private SparseArray<Bitmap> mBitmapCache;
private ProgressBar mLocationLoadingProgressBar;
private LoginValidatorWatcher loginValidatorWatcher;
private static String mLastCorrectURL = "";
private static List<Location> mLocationsList;
final private String initialUrl = OpenMRS.getInstance().getServerUrl();
protected OpenMRS mOpenMRS = OpenMRS.getInstance();
public static LoginFragment newInstance() {
return new LoginFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView = inflater.inflate(R.layout.fragment_login, container, false);
initViewFields(mRootView);
initListeners();
if (mLastCorrectURL.equals(ApplicationConstants.EMPTY_STRING)) {
mUrl.setText(OpenMRS.getInstance().getServerUrl());
mLastCorrectURL = OpenMRS.getInstance().getServerUrl();
} else {
mUrl.setText(mLastCorrectURL);
}
hideURLDialog();
// Font config
FontsUtil.setFont((ViewGroup) this.getActivity().findViewById(android.R.id.content));
return mRootView;
}
private void initListeners() {
mLoginSyncButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(OpenMRS.getInstance());
boolean syncState = prefs.getBoolean("sync", true);
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(OpenMRS.getInstance()).edit();
editor.putBoolean("sync", !syncState);
editor.commit();
setSyncButtonState(!syncState);
}
});
loginValidatorWatcher = new LoginValidatorWatcher(mUrl, mUsername, mPassword, mDropdownLocation, mLoginButton);
mUrl.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if (StringUtils.notEmpty(mUrl.getText().toString())
&& !view.isFocused()
&& loginValidatorWatcher.isUrlChanged()
|| (loginValidatorWatcher.isUrlChanged() && !view.isFocused()
&& loginValidatorWatcher.isLocationErrorOccurred())
|| (!loginValidatorWatcher.isUrlChanged() && !view.isFocused())) {
((LoginFragment) getActivity()
.getSupportFragmentManager()
.findFragmentById(R.id.loginContentFrame))
.setUrl(mUrl.getText().toString());
loginValidatorWatcher.setUrlChanged(false);
}
}
});
mLoginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.login(mUsername.getText().toString(),
mPassword.getText().toString(),
mUrl.getText().toString(),
initialUrl);
}
});
mForgotPass.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
forgotPassword();
}
});
mShowPassword.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
mPassword.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
}
else {
mPassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
}
}
});
}
private void initViewFields(View root) {
mUrl = (EditText) root.findViewById(R.id.loginUrlField);
mUsername = (EditText) root.findViewById(R.id.loginUsernameField);
mUsername.setText(OpenMRS.getInstance().getUsername());
mPassword = (EditText) root.findViewById(R.id.loginPasswordField);
mShowPassword = (CheckBox) root.findViewById(R.id.checkboxShowPassword);
mLoginButton = (Button) root.findViewById(R.id.loginButton);
mSpinner = (ProgressBar) root.findViewById(R.id.loginLoading);
mLoginFormView = (LinearLayout) root.findViewById(R.id.loginFormView);
mLoginSyncButton = ((AppCompatImageView) root.findViewById(R.id.loginSyncButton));
mSyncStateLabel = ((TextView) root.findViewById(R.id.syncLabel));
mDropdownLocation = (Spinner) root.findViewById(R.id.locationSpinner);
mForgotPass = (TextView) root.findViewById(R.id.forgotPass);
mLocationLoadingProgressBar = (ProgressBar) root.findViewById(R.id.locationLoadingProgressBar);
}
@Override
public void onResume() {
super.onResume();
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(OpenMRS.getInstance());
boolean syncState = prefs.getBoolean("sync", true);
setSyncButtonState(syncState);
hideUrlLoadingAnimation();
bindDrawableResources();
}
@Override
public void onDestroy() {
super.onDestroy();
unbindDrawableResources();
}
@Override
public void hideSoftKeys(){
View view = this.getActivity().getCurrentFocus();
if (view == null) {
view = new View(this.getActivity());
}
InputMethodManager inputMethodManager = (InputMethodManager)this.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
private void setSyncButtonState(boolean syncEnabled) {
if (syncEnabled) {
mSyncStateLabel.setText(getString(R.string.login_online));
}
else {
mSyncStateLabel.setText(getString(R.string.login_offline));
}
mLoginSyncButton.setSelected(syncEnabled);
}
public void forgotPassword() {
CustomDialogBundle bundle = new CustomDialogBundle();
bundle.setTitleViewMessage(getString(R.string.forgot_dialog_title));
bundle.setTextViewMessage(getString(R.string.forgot_dialog_message));
bundle.setLeftButtonAction(CustomFragmentDialog.OnClickAction.DISMISS);
bundle.setLeftButtonText(getString(R.string.forgot_button_ok));
((LoginActivity) this.getActivity()).createAndShowDialog(bundle, ApplicationConstants.DialogTAG.LOGOUT_DIALOG_TAG);
}
@Override
public void showWarningDialog() {
CustomDialogBundle bundle = new CustomDialogBundle();
bundle.setTitleViewMessage(getString(R.string.warning_dialog_title));
bundle.setTextViewMessage(getString(R.string.warning_lost_data_dialog));
bundle.setRightButtonText(getString(R.string.dialog_button_ok));
bundle.setRightButtonAction(CustomFragmentDialog.OnClickAction.LOGIN);
bundle.setLeftButtonText(getString(R.string.dialog_button_cancel));
bundle.setLeftButtonAction(CustomFragmentDialog.OnClickAction.DISMISS);
((LoginActivity) this.getActivity()).createAndShowDialog(bundle, ApplicationConstants.DialogTAG.WARNING_LOST_DATA_DIALOG_TAG);
}
@Override
public void showLoadingAnimation() {
mLoginFormView.setVisibility(View.GONE);
mSpinner.setVisibility(View.VISIBLE);
}
@Override
public void hideLoadingAnimation() {
mLoginFormView.setVisibility(View.VISIBLE);
mSpinner.setVisibility(View.GONE);
}
@Override
public void showLocationLoadingAnimation() {
mLoginButton.setEnabled(false);
mLocationLoadingProgressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideUrlLoadingAnimation() {
mLocationLoadingProgressBar.setVisibility(View.INVISIBLE);
mSpinner.setVisibility(View.GONE);
}
@Override
public void finishLoginActivity() {
getActivity().finish();
}
private void bindDrawableResources() {
mBitmapCache = new SparseArray<>();
ImageView openMrsLogoImage = (ImageView) getActivity().findViewById(R.id.openmrsLogo);
createImageBitmap(R.drawable.openmrs_logo, openMrsLogoImage.getLayoutParams());
openMrsLogoImage.setImageBitmap(mBitmapCache.get(R.drawable.openmrs_logo));
}
private void createImageBitmap(Integer key, ViewGroup.LayoutParams layoutParams) {
if (mBitmapCache.get(key) == null) {
mBitmapCache.put(key, ImageUtils.decodeBitmapFromResource(getResources(), key,
layoutParams.width, layoutParams.height));
}
}
private void unbindDrawableResources() {
if (null != mBitmapCache) {
for (int i = 0; i < mBitmapCache.size(); i++) {
Bitmap bitmap = mBitmapCache.valueAt(i);
bitmap.recycle();
}
}
}
public void initLoginForm(List<Location> locationsList, String serverURL) {
setLocationErrorOccurred(false);
mLastCorrectURL = serverURL;
mUrl.setText(serverURL);
mLocationsList = locationsList;
List<String> items = getLocationStringList(locationsList);
final LocationArrayAdapter adapter = new LocationArrayAdapter(this.getActivity(), items);
mDropdownLocation.setAdapter(adapter);
mLoginButton.setEnabled(false);
mSpinner.setVisibility(View.GONE);
mLoginFormView.setVisibility(View.VISIBLE);
}
@Override
public void userAuthenticated() {
Intent intent = new Intent(mOpenMRS.getApplicationContext(), DashboardActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mOpenMRS.getApplicationContext().startActivity(intent);
mPresenter.saveLocationsToDatabase(mLocationsList, mDropdownLocation.getSelectedItem().toString());
}
@Override
public void startFormListService() {
Intent i = new Intent(getContext(), FormListService.class);
getActivity().startService(i);
}
@Override
public void showInvalidURLSnackbar(String message) {
createSnackbar(message)
.setAction(getResources().getString(R.string.snackbar_edit), view -> {
mUrl.requestFocus();
mUrl.selectAll();
})
.show();
}
@Override
public void showInvalidLoginOrPasswordSnackbar() {
String message = getResources().getString(R.string.invalid_login_or_password_message);
createSnackbar(message)
.setAction(getResources().getString(R.string.snackbar_edit), view -> {
mPassword.requestFocus();
mPassword.selectAll();
})
.show();
}
private Snackbar createSnackbar(String message) {
return Snackbar
.make(mRootView, message, Snackbar.LENGTH_LONG);
}
@Override
public void setLocationErrorOccurred(boolean errorOccurred) {
this.loginValidatorWatcher.setLocationErrorOccurred(errorOccurred);
mLoginButton.setEnabled(!errorOccurred);
}
@Override
public void showToast(String message, ToastUtil.ToastType toastType) {
ToastUtil.showShortToast(getContext(), toastType, message);
}
@Override
public void showToast(int textId, ToastUtil.ToastType toastType) {
ToastUtil.showShortToast(getContext(), toastType, getResources().getString(textId));
}
private List<String> getLocationStringList(List<Location> locationList) {
List<String> list = new ArrayList<String>();
list.add(getString(R.string.login_location_select));
for (int i = 0; i < locationList.size(); i++) {
list.add(locationList.get(i).getDisplay());
}
return list;
}
public void setUrl(String url) {
URLValidator.ValidationResult result = URLValidator.validate(url);
if (result.isURLValid()) {
mPresenter.loadLocations(result.getUrl());
} else {
showInvalidURLSnackbar("Invalid URL");
}
}
public void hideURLDialog() {
if (mLocationsList == null) {
mPresenter.loadLocations(mLastCorrectURL);
} else {
initLoginForm(mLocationsList, mLastCorrectURL);
}
}
public void login() {
mPresenter.authenticateUser(mUsername.getText().toString(),
mPassword.getText().toString(),
mUrl.getText().toString());
}
public void login(boolean wipeDatabase) {
mPresenter.authenticateUser(mUsername.getText().toString(),
mPassword.getText().toString(),
mUrl.getText().toString(), wipeDatabase);
}
}