From c5f2ff21c736d0e2473cf2c0f3e2ecece7f19190 Mon Sep 17 00:00:00 2001 From: Javier Varona Date: Tue, 30 Jan 2018 21:44:37 -0400 Subject: [PATCH] - Pin settings is now working - Pin lock screen is almost done (work in progress...) --- app/src/main/AndroidManifest.xml | 2 + .../activities/PinRequestActivity.java | 42 +++++ .../application/CrystalApplication.java | 2 + .../application/CrystalSecurityMonitor.java | 70 +++++++ .../crystalwallet/dao/CryptoCurrencyDao.java | 4 + .../fragments/GeneralSettingsFragment.java | 102 ++++++++++ .../fragments/PinSecurityFragment.java | 177 +++++++++++++++++- .../crystalwallet/models/GeneralSetting.java | 1 + .../service/CrystalWalletService.java | 7 +- .../crystalwallet/util/PasswordManager.java | 22 +++ .../validators/PinSecurityValidator.java | 23 +++ .../CurrentPinValidationField.java | 69 +++++++ .../PinConfirmationValidationField.java | 26 ++- .../validationfields/PinValidationField.java | 23 ++- .../views/CryptoCoinBalanceViewHolder.java | 51 ++--- .../main/res/layout/activity_pin_request.xml | 26 +++ .../res/layout/fragment_general_settings.xml | 4 +- .../main/res/layout/fragment_pin_security.xml | 24 ++- 18 files changed, 626 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/cy/agorise/crystalwallet/activities/PinRequestActivity.java create mode 100644 app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java create mode 100644 app/src/main/java/cy/agorise/crystalwallet/util/PasswordManager.java create mode 100644 app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/PinSecurityValidator.java create mode 100644 app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/CurrentPinValidationField.java create mode 100644 app/src/main/res/layout/activity_pin_request.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 52adab6..90f510b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -36,6 +36,8 @@ + + diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/PinRequestActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/PinRequestActivity.java new file mode 100644 index 0000000..ecc82eb --- /dev/null +++ b/app/src/main/java/cy/agorise/crystalwallet/activities/PinRequestActivity.java @@ -0,0 +1,42 @@ +package cy.agorise.crystalwallet.activities; + +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.Observer; +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.text.Editable; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.OnTextChanged; +import cy.agorise.crystalwallet.R; +import cy.agorise.crystalwallet.models.AccountSeed; +import cy.agorise.crystalwallet.models.GeneralSetting; +import cy.agorise.crystalwallet.viewmodels.AccountSeedViewModel; + +public class PinRequestActivity extends AppCompatActivity { + + @BindView(R.id.etPassword) + EditText etPassword; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_pin_request); + ButterKnife.bind(this); + } + + @OnTextChanged(value = R.id.etPassword, + callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) + void afterPasswordChanged(Editable editable) { + this.finish(); + } +} + + diff --git a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java index fc5f6c7..64e7345 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java +++ b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java @@ -26,5 +26,7 @@ public class CrystalApplication extends Application { Intent intent = new Intent(getApplicationContext(), CrystalWalletService.class); startService(intent); + + registerActivityLifecycleCallbacks(new CrystalSecurityMonitor()); } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java new file mode 100644 index 0000000..c99729d --- /dev/null +++ b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java @@ -0,0 +1,70 @@ +package cy.agorise.crystalwallet.application; + +import android.app.Activity; +import android.app.Application; +import android.content.Intent; +import android.os.Bundle; +import android.widget.Toast; + +import cy.agorise.crystalwallet.activities.CreateSeedActivity; +import cy.agorise.crystalwallet.activities.PinRequestActivity; + +/** + * Created by Henry Varona on 27/1/2018. + */ + +class CrystalSecurityMonitor implements Application.ActivityLifecycleCallbacks { + private int numStarted = 0; + + @Override + public void onActivityStarted(Activity activity) { + if (numStarted == 0) { + callPasswordRequest(activity); + } + numStarted++; + } + + @Override + public void onActivityStopped(Activity activity) { + numStarted--; + if (numStarted == 0) { + callPasswordRequest(activity); + } + } + + public void callPasswordRequest(Activity activity){ + if ((!activity.getIntent().hasExtra("ACTIVITY_TYPE")) || (!activity.getIntent().getStringExtra("ACTIVITY_TYPE").equals("PASSWORD_REQUEST"))) { + //Intent intent = new Intent(activity, PinRequestActivity.class); + //intent.putExtra("ACTIVITY_TYPE", "PASSWORD_REQUEST"); + //activity.startActivity(intent); + } + } + + @Override + public void onActivityCreated(Activity activity, Bundle bundle) { + // + } + + @Override + public void onActivityResumed(Activity activity) { + // + } + + @Override + public void onActivityPaused(Activity activity) { + // + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + // + } + + @Override + public void onActivityDestroyed(Activity activity) { + // + } + + + +} diff --git a/app/src/main/java/cy/agorise/crystalwallet/dao/CryptoCurrencyDao.java b/app/src/main/java/cy/agorise/crystalwallet/dao/CryptoCurrencyDao.java index 6826c4f..f821a35 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/dao/CryptoCurrencyDao.java +++ b/app/src/main/java/cy/agorise/crystalwallet/dao/CryptoCurrencyDao.java @@ -1,5 +1,6 @@ package cy.agorise.crystalwallet.dao; +import android.arch.lifecycle.LiveData; import android.arch.persistence.room.Dao; import android.arch.persistence.room.Insert; import android.arch.persistence.room.OnConflictStrategy; @@ -28,6 +29,9 @@ public interface CryptoCurrencyDao { @Query("SELECT * FROM crypto_currency WHERE id IN (:ids)") List getByIds(List ids); + @Query("SELECT * FROM crypto_currency WHERE name = :name") + LiveData getLiveDataByName(String name); + @Query("SELECT * FROM crypto_currency WHERE name = :name") CryptoCurrency getByName(String name); diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/GeneralSettingsFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/GeneralSettingsFragment.java index 7be6e28..e91e848 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/GeneralSettingsFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/GeneralSettingsFragment.java @@ -1,19 +1,44 @@ package cy.agorise.crystalwallet.fragments; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.Observer; +import android.arch.lifecycle.ViewModelProviders; import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Spinner; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Currency; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; + +import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnItemSelected; import cy.agorise.crystalwallet.R; +import cy.agorise.crystalwallet.models.GeneralSetting; +import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel; /** * Created by xd on 12/28/17. */ public class GeneralSettingsFragment extends Fragment { + + private HashMap countriesMap; + private GeneralSettingListViewModel generalSettingListViewModel; + private LiveData> generalSettingListLiveData; + + @BindView (R.id.spTaxableCountry) + Spinner spTaxableCountry; + public GeneralSettingsFragment() { // Required empty public constructor } @@ -37,6 +62,83 @@ public class GeneralSettingsFragment extends Fragment { View v = inflater.inflate(R.layout.fragment_general_settings, container, false); ButterKnife.bind(this, v); + generalSettingListViewModel = ViewModelProviders.of(this).get(GeneralSettingListViewModel.class); + generalSettingListLiveData = generalSettingListViewModel.getGeneralSettingList(); + + // Initializes the countries spinner + countriesMap = new HashMap(); + String[] countryCodeList = Locale.getISOCountries(); + ArrayList countryAndCurrencyList = new ArrayList(); + String countryAndCurrencyLabel = ""; + for (String countryCode : countryCodeList) { + Locale locale = new Locale("", countryCode); + try { + Currency currency = Currency.getInstance(locale); + countryAndCurrencyLabel = locale.getDisplayCountry() + " (" + currency.getCurrencyCode() + ")"; + countryAndCurrencyList.add(countryAndCurrencyLabel); + countriesMap.put(countryCode, countryAndCurrencyLabel); + countriesMap.put(countryAndCurrencyLabel, countryCode); + } catch (Exception e) { + + } + } + Collections.sort(countryAndCurrencyList); + countryAndCurrencyList.add(0,"SELECT COUNTRY"); + ArrayAdapter countryAdapter = new ArrayAdapter(this.getContext(), android.R.layout.simple_spinner_item, countryAndCurrencyList); + spTaxableCountry.setAdapter(countryAdapter); + + //Observes the general settings data + generalSettingListLiveData.observe(this, new Observer>() { + @Override + public void onChanged(@Nullable List generalSettings) { + loadSettings(generalSettings); + } + }); + return v; } + + public GeneralSetting getSetting(String name){ + for (GeneralSetting generalSetting:this.generalSettingListLiveData.getValue()) { + if (generalSetting.getName().equals(name)) { + return generalSetting; + } + } + + return null; + } + + @OnItemSelected(R.id.spTaxableCountry) + void onItemSelected(int position) { + if (position != 0) { + GeneralSetting generalSettingCountryCode = this.getSetting(GeneralSetting.SETTING_NAME_PREFERED_COUNTRY); + GeneralSetting generalSettingCurrency = this.getSetting(GeneralSetting.SETTING_NAME_PREFERED_CURRENCY); + + if (generalSettingCountryCode == null){ + generalSettingCountryCode = new GeneralSetting(); + generalSettingCountryCode.setName(GeneralSetting.SETTING_NAME_PREFERED_COUNTRY); + } + if (generalSettingCurrency == null){ + generalSettingCurrency = new GeneralSetting(); + generalSettingCurrency.setName(GeneralSetting.SETTING_NAME_PREFERED_CURRENCY); + } + + String countryCode = countriesMap.get((String) spTaxableCountry.getSelectedItem()); + Locale locale = new Locale("", countryCode); + Currency currency = Currency.getInstance(locale); + + generalSettingCountryCode.setValue(countryCode); + generalSettingCurrency.setValue(currency.getCurrencyCode()); + this.generalSettingListViewModel.saveGeneralSettings(generalSettingCountryCode, generalSettingCurrency); + } + } + + public void loadSettings(List generalSettings){ + for (GeneralSetting generalSetting:generalSettings) { + if (generalSetting.getName().equals(GeneralSetting.SETTING_NAME_PREFERED_COUNTRY)){ + String preferedCountryCode = generalSetting.getValue(); + spTaxableCountry.setSelection(((ArrayAdapter)spTaxableCountry.getAdapter()).getPosition(countriesMap.get(preferedCountryCode))); + } + } + } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/PinSecurityFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/PinSecurityFragment.java index 52e2c55..6c75211 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/PinSecurityFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/PinSecurityFragment.java @@ -1,19 +1,60 @@ package cy.agorise.crystalwallet.fragments; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.Observer; +import android.arch.lifecycle.ViewModelProviders; import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.text.Editable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; +import java.util.List; + +import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnTextChanged; import cy.agorise.crystalwallet.R; +import cy.agorise.crystalwallet.activities.CreateSeedActivity; +import cy.agorise.crystalwallet.dao.CrystalDatabase; +import cy.agorise.crystalwallet.models.GeneralSetting; +import cy.agorise.crystalwallet.util.PasswordManager; +import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel; +import cy.agorise.crystalwallet.viewmodels.validators.PinSecurityValidator; +import cy.agorise.crystalwallet.viewmodels.validators.UIValidatorListener; +import cy.agorise.crystalwallet.viewmodels.validators.validationfields.ValidationField; /** * Created by xd on 1/18/18. */ -public class PinSecurityFragment extends Fragment { +public class PinSecurityFragment extends Fragment implements UIValidatorListener { + + @BindView(R.id.tvCurrentPin) + TextView tvCurrentPin; + @BindView(R.id.etCurrentPin) + EditText etCurrentPin; + @BindView(R.id.etNewPin) + EditText etNewPin; + @BindView(R.id.etConfirmPin) + EditText etConfirmPin; + + @BindView(R.id.tvCurrentPinError) + TextView tvCurrentPinError; + @BindView(R.id.tvNewPinError) + TextView tvNewPinError; + @BindView(R.id.tvConfirmPinError) + TextView tvConfirmPinError; + + GeneralSettingListViewModel generalSettingListViewModel; + GeneralSetting passwordGeneralSetting; + PinSecurityValidator pinSecurityValidator; public PinSecurityFragment() { // Required empty public constructor @@ -33,6 +74,140 @@ public class PinSecurityFragment extends Fragment { View v = inflater.inflate(R.layout.fragment_pin_security, container, false); ButterKnife.bind(this, v); + generalSettingListViewModel = ViewModelProviders.of(this).get(GeneralSettingListViewModel.class); + LiveData> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList(); + + pinSecurityValidator = new PinSecurityValidator(this.getContext(), etCurrentPin, etNewPin, etConfirmPin); + pinSecurityValidator.setListener(this); + + generalSettingsLiveData.observe(this, new Observer>() { + @Override + public void onChanged(@Nullable List generalSettings) { + boolean founded = false; + + if (generalSettings != null){ + for (GeneralSetting generalSetting:generalSettings) { + if (generalSetting.getName().equals(GeneralSetting.SETTING_PASSWORD)){ + founded = true; + if (!generalSetting.getValue().isEmpty()){ + passwordGeneralSetting = generalSetting; + showCurrentPinUI(true); + } else { + showCurrentPinUI(false); + } + break; + } + } + if (!founded){ + showCurrentPinUI(false); + } + } else { + showCurrentPinUI(false); + } + } + }); + return v; } + + public void showCurrentPinUI(Boolean visible){ + if (visible){ + tvCurrentPin.setVisibility(View.VISIBLE); + etCurrentPin.setVisibility(View.VISIBLE); + } else { + tvCurrentPin.setVisibility(View.GONE); + etCurrentPin.setVisibility(View.GONE); + } + } + + @OnTextChanged(value = R.id.etCurrentPin, + callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) + void afterCurrentPinChanged(Editable editable) { + this.pinSecurityValidator.validate(); + } + + @OnTextChanged(value = R.id.etNewPin, + callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) + void afterNewPinChanged(Editable editable) { + this.pinSecurityValidator.validate(); + } + + @OnTextChanged(value = R.id.etConfirmPin, + callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) + void afterConfirmPinChanged(Editable editable) { + this.pinSecurityValidator.validate(); + } + + public void clearFields(){ + if (!this.etCurrentPin.getText().toString().equals("")) { + this.etCurrentPin.setText(""); + } + if (!this.etNewPin.getText().toString().equals("")) { + this.etNewPin.setText(""); + } + if (!this.etConfirmPin.getText().toString().equals("")) { + this.etConfirmPin.setText(""); + } + } + + @Override + public void onValidationSucceeded(final ValidationField field) { + final PinSecurityFragment fragment = this; + + this.getActivity().runOnUiThread(new Runnable() { + public void run() { + + if (field.getView() == etCurrentPin) { + tvCurrentPinError.setText(""); + } else if (field.getView() == etNewPin){ + tvNewPinError.setText(""); + } else if (field.getView() == etConfirmPin){ + tvConfirmPinError.setText(""); + } + + if (pinSecurityValidator.isValid()){ + CharSequence text = "Your password has been sucessfully changed!"; + int duration = Toast.LENGTH_SHORT; + + Toast toast = Toast.makeText(getContext(), text, duration); + toast.show(); + //showCurrentPinUI(true); + + savePassword(etNewPin.getText().toString()); + + + clearFields(); + } + } + }); + } + + public void savePassword(String password) { + String passwordEncripted = PasswordManager.encriptPassword(password); + + if (passwordGeneralSetting == null) { + passwordGeneralSetting = new GeneralSetting(); + passwordGeneralSetting.setName(GeneralSetting.SETTING_PASSWORD); + } + + passwordGeneralSetting.setValue(passwordEncripted); + generalSettingListViewModel.saveGeneralSetting(passwordGeneralSetting); + } + + @Override + public void onValidationFailed(final ValidationField field) { + this.getActivity().runOnUiThread(new Runnable() { + + @Override + public void run() { + if (field.getView() == etCurrentPin) { + tvCurrentPinError.setText(field.getMessage()); + } else if (field.getView() == etNewPin){ + tvNewPinError.setText(field.getMessage()); + } else if (field.getView() == etConfirmPin){ + tvConfirmPinError.setText(field.getMessage()); + } + } + }); + } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/models/GeneralSetting.java b/app/src/main/java/cy/agorise/crystalwallet/models/GeneralSetting.java index b5b322d..822a10e 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/models/GeneralSetting.java +++ b/app/src/main/java/cy/agorise/crystalwallet/models/GeneralSetting.java @@ -17,6 +17,7 @@ public class GeneralSetting { public final static String SETTING_NAME_PREFERED_COUNTRY = "PREFERED_COUNTRY"; public final static String SETTING_NAME_PREFERED_CURRENCY = "PREFERED_CURRENCY"; + public final static String SETTING_PASSWORD = "PASSWORD"; /** * The id on the database diff --git a/app/src/main/java/cy/agorise/crystalwallet/service/CrystalWalletService.java b/app/src/main/java/cy/agorise/crystalwallet/service/CrystalWalletService.java index 5cecb10..93b89a5 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/service/CrystalWalletService.java +++ b/app/src/main/java/cy/agorise/crystalwallet/service/CrystalWalletService.java @@ -109,8 +109,7 @@ public class CrystalWalletService extends LifecycleService { if (LoadEquivalencesThread != null) { LoadEquivalencesThread.stopLoadingEquivalences(); - } - ; + }; LoadEquivalencesThread = new EquivalencesThread(service, generalSetting.getValue(), bitsharesAssets); LoadEquivalencesThread.start(); } @@ -184,14 +183,14 @@ public class CrystalWalletService extends LifecycleService { } //if (LoadEquivalencesThread == null) { - // LoadEquivalencesThread = new Thread() { + // LoadEquivalencesThread = new EquivalencesThread() { // @Override // public void run() { loadEquivalentsValues(); // } // }; // LoadEquivalencesThread.start(); - //} + // } // If we get killed, after returning from here, restart return START_STICKY; diff --git a/app/src/main/java/cy/agorise/crystalwallet/util/PasswordManager.java b/app/src/main/java/cy/agorise/crystalwallet/util/PasswordManager.java new file mode 100644 index 0000000..7f52970 --- /dev/null +++ b/app/src/main/java/cy/agorise/crystalwallet/util/PasswordManager.java @@ -0,0 +1,22 @@ +package cy.agorise.crystalwallet.util; + +/** + * Created by Henry Varona on 29/1/2018. + */ + +public class PasswordManager { + + //TODO implement password checking using the encryption implemented in encriptPassword + public static boolean checkPassword(String encriptedPassword, String passwordToCheck){ + if (encriptedPassword.equals(passwordToCheck)){ + return true; + } else { + return false; + } + } + + //TODO implement password encryption + public static String encriptPassword(String password){ + return password; + } +} diff --git a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/PinSecurityValidator.java b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/PinSecurityValidator.java new file mode 100644 index 0000000..b99f155 --- /dev/null +++ b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/PinSecurityValidator.java @@ -0,0 +1,23 @@ +package cy.agorise.crystalwallet.viewmodels.validators; + +import android.content.Context; +import android.widget.EditText; + +import cy.agorise.crystalwallet.viewmodels.validators.validationfields.BitsharesAccountNameDoesntExistsValidationField; +import cy.agorise.crystalwallet.viewmodels.validators.validationfields.CurrentPinValidationField; +import cy.agorise.crystalwallet.viewmodels.validators.validationfields.PinConfirmationValidationField; +import cy.agorise.crystalwallet.viewmodels.validators.validationfields.PinValidationField; + +/** + * Created by Henry Varona on 1/28/2018. + */ + +public class PinSecurityValidator extends UIValidator { + + public PinSecurityValidator(Context context, EditText currentPinEdit, EditText newPinEdit, EditText newPinConfirmationEdit){ + super(context); + this.addField(new CurrentPinValidationField(currentPinEdit)); + this.addField(new PinValidationField(newPinEdit)); + this.addField(new PinConfirmationValidationField(newPinEdit,newPinConfirmationEdit)); + } +} diff --git a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/CurrentPinValidationField.java b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/CurrentPinValidationField.java new file mode 100644 index 0000000..7877184 --- /dev/null +++ b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/CurrentPinValidationField.java @@ -0,0 +1,69 @@ +package cy.agorise.crystalwallet.viewmodels.validators.validationfields; + +import android.arch.lifecycle.LifecycleOwner; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.Observer; +import android.arch.lifecycle.ViewModelProviders; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.widget.EditText; + +import java.util.List; + +import cy.agorise.crystalwallet.models.GeneralSetting; +import cy.agorise.crystalwallet.util.PasswordManager; +import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel; + +/** + * Created by Henry Varona on 1/28/2018. + */ + +public class CurrentPinValidationField extends ValidationField { + + private EditText currentPinField; + String currentPassword = ""; + + public CurrentPinValidationField(EditText currentPinField){ + super(currentPinField); + this.currentPinField = currentPinField; + GeneralSettingListViewModel generalSettingListViewModel = ViewModelProviders.of((FragmentActivity)view.getContext()).get(GeneralSettingListViewModel.class); + LiveData> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList(); + generalSettingsLiveData.observe((LifecycleOwner) this.view.getContext(), new Observer>() { + @Override + public void onChanged(@Nullable List generalSettings) { + for (GeneralSetting generalSetting:generalSettings) { + if (generalSetting.getName().equals(GeneralSetting.SETTING_PASSWORD)){ + currentPassword = generalSetting.getValue(); + break; + } + } + } + }); + } + + public void validate(){ + final String newValue = currentPinField.getText().toString(); + + if (this.currentPassword.equals("")) { + this.setLastValue(""); + this.startValidating(); + setValidForValue("",true); + } else if (!newValue.equals(this.getLastValue())) { + this.setLastValue(newValue); + this.startValidating(); + if (newValue.equals("")){ + setMessageForValue(lastValue, ""); + setValidForValue(lastValue, false); + } else { + + if (PasswordManager.checkPassword(this.currentPassword, newValue)) { + setValidForValue(lastValue, true); + } else { + setMessageForValue(lastValue, "Password is invalid."); + setValidForValue(lastValue, false); + } + } + } + } +} diff --git a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/PinConfirmationValidationField.java b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/PinConfirmationValidationField.java index 00f951e..77b7043 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/PinConfirmationValidationField.java +++ b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/PinConfirmationValidationField.java @@ -22,18 +22,24 @@ public class PinConfirmationValidationField extends ValidationField { public void validate(){ String newConfirmationValue = pinConfirmationField.getText().toString(); String newValue = pinField.getText().toString(); - String mixedValue = newValue+"_"+newConfirmationValue; - if (mixedValue != this.getLastValue()) { - this.setLastValue(mixedValue); - this.startValidating(); + String mixedValue = newValue + "_" + newConfirmationValue; - - if (!newConfirmationValue.equals(newValue)){ - this.setMessageForValue(mixedValue,this.validator.getContext().getResources().getString(R.string.mismatch_pin)); - this.setValidForValue(mixedValue,false); - } else { - this.setValidForValue(mixedValue, true); + if (!newConfirmationValue.equals("")) { + if (!mixedValue.equals(this.getLastValue())) { + this.setLastValue(mixedValue); + this.startValidating(); + if (!newConfirmationValue.equals(newValue)) { + this.setMessageForValue(mixedValue, this.validator.getContext().getResources().getString(R.string.mismatch_pin)); + this.setValidForValue(mixedValue, false); + } else { + this.setValidForValue(mixedValue, true); + } } + } else { + this.setLastValue(""); + this.startValidating(); + this.setMessageForValue("", ""); + this.setValidForValue("", false); } } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/PinValidationField.java b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/PinValidationField.java index 809b8c6..6228641 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/PinValidationField.java +++ b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/PinValidationField.java @@ -20,16 +20,23 @@ public class PinValidationField extends ValidationField { public void validate(){ String newValue = pinField.getText().toString(); - if (newValue != this.getLastValue()) { - this.setLastValue(newValue); - this.startValidating(); + if (!newValue.equals("")) { + if (!newValue.equals(this.getLastValue())) { + this.setLastValue(newValue); + this.startValidating(); - if (newValue.length() < 6) { - this.setMessageForValue(newValue, this.validator.getContext().getResources().getString(R.string.pin_number_warning)); - this.setValidForValue(newValue, false); - } else { - this.setValidForValue(newValue, true); + if (newValue.length() < 6) { + this.setMessageForValue(newValue, this.validator.getContext().getResources().getString(R.string.pin_number_warning)); + this.setValidForValue(newValue, false); + } else { + this.setValidForValue(newValue, true); + } } + } else { + this.setLastValue(""); + this.startValidating(); + this.setMessageForValue("", ""); + this.setValidForValue("", false); } } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java index a17cb05..45e0168 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java +++ b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java @@ -80,30 +80,39 @@ public class CryptoCoinBalanceViewHolder extends RecyclerView.ViewHolder { public void onChanged(@Nullable GeneralSetting generalSetting) { if (generalSetting != null) { //Gets the currency object of the preferred currency - CryptoCurrency currencyTo = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getByName(generalSetting.getValue()); + LiveData currencyToLiveData = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getLiveDataByName(generalSetting.getValue()); - //Retrieves the equivalent value of this balance using the "From" currency and the "To" currency - LiveData currencyEquivalenceLiveData = CrystalDatabase.getAppDatabase(context) - .cryptoCurrencyEquivalenceDao().getByFromTo( - currencyTo.getId(), - currencyFrom.getId() - - ); - - //Observes the equivalent value. If the equivalent value changes, this will keep the value showed correct - currencyEquivalenceLiveData.observe((LifecycleOwner) context, new Observer() { + currencyToLiveData.observe((LifecycleOwner) context, new Observer() { @Override - public void onChanged(@Nullable CryptoCurrencyEquivalence cryptoCurrencyEquivalence) { - if (cryptoCurrencyEquivalence != null) { - CryptoCurrency toCurrency = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getById(cryptoCurrencyEquivalence.getFromCurrencyId()); - String equivalenceString = String.format( - "%.2f", - (balance.getBalance()/Math.pow(10,currencyFrom.getPrecision()))/ - (cryptoCurrencyEquivalence.getValue()/Math.pow(10,toCurrency.getPrecision())) - ); + public void onChanged(@Nullable CryptoCurrency cryptoCurrency) { + if (cryptoCurrency != null) { + CryptoCurrency currencyTo = cryptoCurrency; - cryptoCoinBalanceEquivalence.setText( - equivalenceString + " " + toCurrency.getName()); + //Retrieves the equivalent value of this balance using the "From" currency and the "To" currency + LiveData currencyEquivalenceLiveData = CrystalDatabase.getAppDatabase(context) + .cryptoCurrencyEquivalenceDao().getByFromTo( + currencyTo.getId(), + currencyFrom.getId() + + ); + + //Observes the equivalent value. If the equivalent value changes, this will keep the value showed correct + currencyEquivalenceLiveData.observe((LifecycleOwner) context, new Observer() { + @Override + public void onChanged(@Nullable CryptoCurrencyEquivalence cryptoCurrencyEquivalence) { + if (cryptoCurrencyEquivalence != null) { + CryptoCurrency toCurrency = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getById(cryptoCurrencyEquivalence.getFromCurrencyId()); + String equivalenceString = String.format( + "%.2f", + (balance.getBalance() / Math.pow(10, currencyFrom.getPrecision())) / + (cryptoCurrencyEquivalence.getValue() / Math.pow(10, toCurrency.getPrecision())) + ); + + cryptoCoinBalanceEquivalence.setText( + equivalenceString + " " + toCurrency.getName()); + } + } + }); } } }); diff --git a/app/src/main/res/layout/activity_pin_request.xml b/app/src/main/res/layout/activity_pin_request.xml new file mode 100644 index 0000000..58fa56f --- /dev/null +++ b/app/src/main/res/layout/activity_pin_request.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_general_settings.xml b/app/src/main/res/layout/fragment_general_settings.xml index 6364bb0..257d0f2 100644 --- a/app/src/main/res/layout/fragment_general_settings.xml +++ b/app/src/main/res/layout/fragment_general_settings.xml @@ -56,9 +56,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="8dp" - app:layout_constraintTop_toBottomOf="@+id/tvTaxableCountry" + app:layout_constraintEnd_toEndOf="@id/spBackupAsset" app:layout_constraintStart_toStartOf="@id/spBackupAsset" - app:layout_constraintEnd_toEndOf="@id/spBackupAsset"/> + app:layout_constraintTop_toBottomOf="@+id/tvTaxableCountry" /> + + + app:layout_constraintTop_toBottomOf="@+id/tvCurrentPinError" /> + - + app:layout_constraintTop_toBottomOf="@+id/tvNewPinError" /> + \ No newline at end of file