From 0856dceb97f7ea1ba84afdf47ae1a480d34ed4d0 Mon Sep 17 00:00:00 2001 From: ssabeerahamed Date: Fri, 11 Dec 2020 15:52:43 +0530 Subject: [PATCH 01/33] DTSERWFOUR -210 - Update transfer method information --- ...sferMethodConfigurationRepositoryImpl.java | 5 + .../repository/TransferMethodRepository.java | 11 ++ .../TransferMethodRepositoryFactory.java | 7 + .../TransferMethodRepositoryImpl.java | 144 ++++++++++++++- ...erMethodUpdateConfigurationRepository.java | 60 +++++++ ...thodUpdateConfigurationRepositoryImpl.java | 167 ++++++++++++++++++ 6 files changed, 390 insertions(+), 4 deletions(-) create mode 100644 transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepository.java create mode 100644 transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImpl.java diff --git a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImpl.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImpl.java index c953ff758..3af89245b 100644 --- a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImpl.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImpl.java @@ -184,6 +184,11 @@ class FieldMapKey { this.mTransferMethodType = mTransferMethodType; } + FieldMapKey(String mTransferMethodType) { + this.mCountry = null; + this.mCurrency = null; + this.mTransferMethodType = mTransferMethodType; + } private String getCountry() { return mCountry; } diff --git a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepository.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepository.java index f11f896c5..d94d7279c 100644 --- a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepository.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepository.java @@ -46,6 +46,17 @@ void createTransferMethod(@NonNull TransferMethod transferMethod, */ void loadTransferMethods(@NonNull LoadTransferMethodListCallback callback); + + /** + * Update transfer method specified. + * + * @param transferMethod transfer method to deactivate @see {@link TransferMethod} + * @param callback @see {@link DeactivateTransferMethodCallback} + */ + void updateTransferMethod(@NonNull final TransferMethod transferMethod, + @NonNull LoadTransferMethodCallback callback); + + /** * Load latest transfer methods available, associated with current context * diff --git a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactory.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactory.java index ed9360c6f..c5d0b9834 100644 --- a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactory.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactory.java @@ -20,10 +20,12 @@ public class TransferMethodRepositoryFactory { private static TransferMethodRepositoryFactory sInstance; private TransferMethodRepository mTransferMethodRepository; private TransferMethodConfigurationRepository mTransferMethodConfigurationRepository; + private TransferMethodUpdateConfigurationRepository mUpdateTransferMethodConfigurationRepository; private TransferMethodRepositoryFactory() { mTransferMethodRepository = new TransferMethodRepositoryImpl(); mTransferMethodConfigurationRepository = new TransferMethodConfigurationRepositoryImpl(); + mUpdateTransferMethodConfigurationRepository = new TransferMethodUpdateConfigurationRepositoryImpl(); } public static synchronized TransferMethodRepositoryFactory getInstance() { @@ -44,4 +46,9 @@ public TransferMethodRepository getTransferMethodRepository() { public TransferMethodConfigurationRepository getTransferMethodConfigurationRepository() { return mTransferMethodConfigurationRepository; } + + public TransferMethodUpdateConfigurationRepository getUpdateTransferMethodConfigurationRepository() { + return mUpdateTransferMethodConfigurationRepository; + } + } diff --git a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImpl.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImpl.java index 89299912f..4cd261cae 100644 --- a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImpl.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImpl.java @@ -123,6 +123,31 @@ public Handler getHandler() { }); } + @Override + public void updateTransferMethod(@NonNull TransferMethod transferMethod, + @NonNull LoadTransferMethodCallback callback) { + switch (transferMethod.getField(TYPE)) { + case BANK_ACCOUNT: + case WIRE_ACCOUNT: + updateBankAccount(transferMethod, callback); + break; + case BANK_CARD: + updateBankCard(transferMethod, callback); + break; + case PAYPAL_ACCOUNT: + updatePayPalAccount(transferMethod, callback); + break; + case VENMO_ACCOUNT: + updateVenmoAccount(transferMethod, callback); + break; + case PAPER_CHECK: + updatePaperCheck(transferMethod, callback); + break; + default: // error on unknown transfer type + callback.onError(getErrorsOnUnsupportedTransferType()); + } + } + /** * @see TransferMethodRepository#loadLatestTransferMethod(LoadTransferMethodCallback) */ @@ -247,7 +272,7 @@ public Handler getHandler() { } private void deactivateVenmoAccount(@NonNull final TransferMethod transferMethod, - @NonNull final DeactivateTransferMethodCallback callback) { + @NonNull final DeactivateTransferMethodCallback callback) { getHyperwallet().deactivateVenmoAccount(transferMethod.getField(TOKEN), null, new HyperwalletListener() { @Override @@ -289,7 +314,7 @@ public Handler getHandler() { } private void createBankAccount(final TransferMethod transferMethod, - final LoadTransferMethodCallback callback) { + final LoadTransferMethodCallback callback) { BankAccount bankAccount = (BankAccount) transferMethod; getHyperwallet().createBankAccount(bankAccount, new HyperwalletListener() { @@ -333,7 +358,7 @@ public Handler getHandler() { } private void createPayPalAccount(@NonNull final TransferMethod transferMethod, - @NonNull final LoadTransferMethodCallback callback) { + @NonNull final LoadTransferMethodCallback callback) { PayPalAccount payPalAccount = (PayPalAccount) transferMethod; getHyperwallet().createPayPalAccount(payPalAccount, new HyperwalletListener() { @@ -355,7 +380,7 @@ public Handler getHandler() { } private void createVenmoAccount(@NonNull final TransferMethod transferMethod, - @NonNull final LoadTransferMethodCallback callback) { + @NonNull final LoadTransferMethodCallback callback) { VenmoAccount venmoAccount = (VenmoAccount) transferMethod; getHyperwallet().createVenmoAccount(venmoAccount, new HyperwalletListener() { @@ -405,4 +430,115 @@ private Errors getErrorsOnUnsupportedTransferType() { EC_UNEXPECTED_EXCEPTION); return new Errors(Collections.singletonList(error)); } + + private void updateBankAccount(final TransferMethod transferMethod, + final LoadTransferMethodCallback callback) { + BankAccount bankAccount = (BankAccount) transferMethod; + + getHyperwallet().updateBankAccount(bankAccount, new HyperwalletListener() { + @Override + public void onSuccess(@Nullable BankAccount result) { + callback.onTransferMethodLoaded(result); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + + private void updateBankCard(@NonNull final TransferMethod transferMethod, + @NonNull final LoadTransferMethodCallback callback) { + BankCard bankCard = (BankCard) transferMethod; + + getHyperwallet().updateBankCard(bankCard, new HyperwalletListener() { + @Override + public void onSuccess(@Nullable BankCard result) { + callback.onTransferMethodLoaded(result); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + + private void updatePayPalAccount(@NonNull final TransferMethod transferMethod, + @NonNull final LoadTransferMethodCallback callback) { + PayPalAccount payPalAccount = (PayPalAccount) transferMethod; + + getHyperwallet().createPayPalAccount(payPalAccount, new HyperwalletListener() { + @Override + public void onSuccess(@Nullable PayPalAccount result) { + callback.onTransferMethodLoaded(result); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + + private void updateVenmoAccount(@NonNull final TransferMethod transferMethod, + @NonNull final LoadTransferMethodCallback callback) { + VenmoAccount venmoAccount = (VenmoAccount) transferMethod; + + getHyperwallet().createVenmoAccount(venmoAccount, new HyperwalletListener() { + @Override + public void onSuccess(@Nullable VenmoAccount result) { + callback.onTransferMethodLoaded(result); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + + private void updatePaperCheck(@NonNull final TransferMethod transferMethod, + @NonNull final LoadTransferMethodCallback callback) { + PaperCheck paperCheck = (PaperCheck) transferMethod; + + getHyperwallet().createPaperCheck(paperCheck, new HyperwalletListener() { + @Override + public void onSuccess(@Nullable PaperCheck result) { + callback.onTransferMethodLoaded(result); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + } diff --git a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepository.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepository.java new file mode 100644 index 000000000..1e0040dac --- /dev/null +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepository.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Hyperwallet + * + * 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 com.hyperwallet.android.ui.transfermethod.repository; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.hyperwallet.android.model.Errors; +import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; +import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationKey; + +public interface TransferMethodUpdateConfigurationRepository { + + void getKeys(@NonNull final LoadKeysCallback loadKeysCallback); + + void getFields(@NonNull final String transferMethodType, + @NonNull final LoadFieldsCallback loadFieldsCallback); + + void refreshKeys(); + + void refreshFields(); + + interface LoadKeysCallback { + + void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKey transferMethodConfigurationKey); + + void onError(@NonNull final Errors errors); + } + + interface LoadFieldsCallback { + + void onFieldsLoaded(@Nullable final HyperwalletTransferMethodConfigurationField field); + + void onError(@NonNull final Errors errors); + } +} diff --git a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImpl.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImpl.java new file mode 100644 index 000000000..1bbfb956d --- /dev/null +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImpl.java @@ -0,0 +1,167 @@ +/* + * Copyright 2018 Hyperwallet + * + * 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 com.hyperwallet.android.ui.transfermethod.repository; + +import android.os.Handler; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.listener.HyperwalletListener; +import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; +import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationKey; +import com.hyperwallet.android.model.graphql.query.TransferMethodConfigurationKeysQuery; +import com.hyperwallet.android.model.graphql.query.TransferMethodUpdateConfigurationFieldQuery; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; + +import java.util.HashMap; +import java.util.Map; + +public class TransferMethodUpdateConfigurationRepositoryImpl implements TransferMethodUpdateConfigurationRepository { + private final Handler mHandler; + private final Map mFieldMap; + private HyperwalletTransferMethodConfigurationKey mTransferMethodConfigurationKey; + + //todo use default modifier after RepositoryFactory is removed + public TransferMethodUpdateConfigurationRepositoryImpl() { + mHandler = new Handler(); + mFieldMap = new HashMap<>(); + } + + @VisibleForTesting() + protected TransferMethodUpdateConfigurationRepositoryImpl(@Nullable Handler handler, + HyperwalletTransferMethodConfigurationKey transferMethodConfigurationKey, + Map fieldMap) { + mHandler = handler; + mTransferMethodConfigurationKey = transferMethodConfigurationKey; + mFieldMap = fieldMap; + } + + @VisibleForTesting + Hyperwallet getHyperwallet() { + return Hyperwallet.getDefault(); + } + + @VisibleForTesting + void getTransferMethodConfigurationKeyResult(final LoadKeysCallback loadKeysCallback) { + TransferMethodConfigurationKeysQuery query = new TransferMethodConfigurationKeysQuery(); + EspressoIdlingResource.increment(); + + getHyperwallet().retrieveTransferMethodConfigurationKeys(query, + new HyperwalletListener() { + @Override + public void onSuccess(@Nullable HyperwalletTransferMethodConfigurationKey result) { + mTransferMethodConfigurationKey = result; + loadKeysCallback.onKeysLoaded(mTransferMethodConfigurationKey); + EspressoIdlingResource.decrement(); + } + + @Override + public void onFailure(HyperwalletException exception) { + loadKeysCallback.onError(exception.getErrors()); + EspressoIdlingResource.decrement(); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + + + @VisibleForTesting + void getTransferMethodConfigurationFieldResult( + @NonNull final String transferMethodType, + @NonNull final LoadFieldsCallback loadFieldsCallback) { + TransferMethodUpdateConfigurationFieldQuery query = new TransferMethodUpdateConfigurationFieldQuery( + transferMethodType); + EspressoIdlingResource.increment(); + + getHyperwallet().retrieveUpdateTransferMethodConfigurationFields( + query, + new HyperwalletListener() { + @Override + public void onSuccess(HyperwalletTransferMethodConfigurationField result) { + FieldMapKey fieldMapKey = new FieldMapKey(transferMethodType); + mFieldMap.put(fieldMapKey, result); + loadFieldsCallback.onFieldsLoaded(result); + EspressoIdlingResource.decrement(); + } + + @Override + public void onFailure(HyperwalletException exception) { + loadFieldsCallback.onError(exception.getErrors()); + EspressoIdlingResource.decrement(); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + + } + + @Override + public synchronized void getKeys(@NonNull final LoadKeysCallback loadKeysCallback) { + if (mTransferMethodConfigurationKey == null) { + getTransferMethodConfigurationKeyResult(loadKeysCallback); + } else { + loadKeysCallback.onKeysLoaded(mTransferMethodConfigurationKey); + } + } + + @Override + public synchronized void getFields(@NonNull final String transferMethodType, + @NonNull final LoadFieldsCallback loadFieldsCallback) { + + FieldMapKey fieldMapKey = new FieldMapKey(transferMethodType); + HyperwalletTransferMethodConfigurationField transferMethodConfigurationField = mFieldMap.get(fieldMapKey); + // if there is no value for country-currency-type combination, + // it means api call was never made or this combination or it was refreshed + if (transferMethodConfigurationField == null) { + getTransferMethodConfigurationFieldResult(transferMethodType, loadFieldsCallback); + } else { + loadFieldsCallback.onFieldsLoaded(transferMethodConfigurationField); + } + } + + @Override + public void refreshKeys() { + mTransferMethodConfigurationKey = null; + } + + @Override + public void refreshFields() { + mFieldMap.clear(); + } + +} \ No newline at end of file From 747f462a3acdded2da8dce17488459c43c760937 Mon Sep 17 00:00:00 2001 From: ssabeerahamed Date: Mon, 14 Dec 2020 20:30:39 +0530 Subject: [PATCH 02/33] DTSERWFOUR-210- added Unit test --- .../transfermethod/repository/FieldMapKeyTest.java | 13 ++++++++++++- .../TransferMethodRepositoryFactoryTest.java | 5 +++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/FieldMapKeyTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/FieldMapKeyTest.java index f0541bb9a..4da7c75e4 100644 --- a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/FieldMapKeyTest.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/FieldMapKeyTest.java @@ -13,6 +13,12 @@ public void testEquals_withSameReference() { assertEquals(thisKey, thisKey); } + @Test + public void testEquals_withSameReference_withAnotherConstructor() { + FieldMapKey thisKey = new FieldMapKey("BANK_ACCOUNT"); + assertEquals(thisKey, thisKey); + } + @Test public void testEquals_withDifferentObjectType() { FieldMapKey thisKey = new FieldMapKey("US", "USD", "BANK_ACCOUNT"); @@ -33,5 +39,10 @@ public void testEquals_withDifferentReferencesDifferentValues() { FieldMapKey thatKey = new FieldMapKey("CA", "CAD", "BANK_ACCOUNT"); assertNotEquals(thisKey, thatKey); } - + @Test + public void testEquals_withDifferentReferencesDifferentValues_withConstructor() { + FieldMapKey thisKey = new FieldMapKey("BANK_ACCOUNT"); + FieldMapKey thatKey = new FieldMapKey("BANK_CARD"); + assertNotEquals(thisKey, thatKey); + } } diff --git a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactoryTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactoryTest.java index 7e89c5a03..ac8da0d9f 100644 --- a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactoryTest.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactoryTest.java @@ -14,6 +14,7 @@ public void testGetInstance_verifyRepositoriesInitialized() { assertThat(repositoryFactory, is(notNullValue())); assertThat(repositoryFactory.getTransferMethodRepository(), is(notNullValue())); assertThat(repositoryFactory.getTransferMethodConfigurationRepository(), is(notNullValue())); + assertThat(repositoryFactory.getUpdateTransferMethodConfigurationRepository(), is(notNullValue())); } @Test @@ -23,10 +24,13 @@ public void testClearInstance_verifyRepositoryCleared() { TransferMethodRepository transferMethodRepository = repositoryFactory.getTransferMethodRepository(); TransferMethodConfigurationRepository configurationRepository = repositoryFactory.getTransferMethodConfigurationRepository(); + TransferMethodUpdateConfigurationRepository transferMethodUpdateConfigurationRepository = + repositoryFactory.getUpdateTransferMethodConfigurationRepository(); TransferMethodRepositoryFactory currentRepositoryFactory = TransferMethodRepositoryFactory.getInstance(); assertThat(repositoryFactory, is(currentRepositoryFactory)); assertThat(transferMethodRepository, is(currentRepositoryFactory.getTransferMethodRepository())); assertThat(configurationRepository, is(currentRepositoryFactory.getTransferMethodConfigurationRepository())); + assertThat(transferMethodUpdateConfigurationRepository,is(currentRepositoryFactory.getUpdateTransferMethodConfigurationRepository())); TransferMethodRepositoryFactory.clearInstance(); @@ -35,5 +39,6 @@ public void testClearInstance_verifyRepositoryCleared() { assertThat(transferMethodRepository, is(not(anotherRepositoryFactory.getTransferMethodRepository()))); assertThat(configurationRepository, is(not(anotherRepositoryFactory.getTransferMethodConfigurationRepository()))); + assertThat(transferMethodUpdateConfigurationRepository,is(not(anotherRepositoryFactory.getUpdateTransferMethodConfigurationRepository()))); } } \ No newline at end of file From a2f888cff32cfb29710cf4fe745292db0bf2f5b6 Mon Sep 17 00:00:00 2001 From: ssabeerahamed Date: Mon, 14 Dec 2020 21:21:51 +0530 Subject: [PATCH 03/33] DTSERWFOUR-210- update widget --- .../android/ui/transfermethod/view/widget/AbstractWidget.java | 2 ++ .../android/ui/transfermethod/view/widget/NumberWidget.java | 2 +- .../android/ui/transfermethod/view/widget/SelectionWidget.java | 1 + .../android/ui/transfermethod/view/widget/TextWidget.java | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/AbstractWidget.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/AbstractWidget.java index 3db0c5618..19db4d756 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/AbstractWidget.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/AbstractWidget.java @@ -36,6 +36,7 @@ public abstract class AbstractWidget { protected final WidgetEventListener mListener; protected int mBottomViewId = 0; protected WidgetInputState mWidgetInputState; + public Boolean isEdited; public AbstractWidget(@Nullable Field field, @NonNull WidgetEventListener listener, @Nullable String defaultValue, @NonNull View defaultFocusView) { @@ -169,6 +170,7 @@ public boolean onKey(View v, int keyCode, KeyEvent event) { case KeyEvent.KEYCODE_ENTER: mFocusView.requestFocus(); mClearFocusView.clearFocus(); + isEdited = true; return true; default: break; diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/NumberWidget.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/NumberWidget.java index 2b1e5a70e..270d267f6 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/NumberWidget.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/NumberWidget.java @@ -59,7 +59,7 @@ public View getView(@NonNull final ViewGroup viewGroup) { editText.setEnabled(mField.isEditable()); setIdFromFieldLabel(mTextInputLayout); setIdFromFieldName(editText); - + isEdited = true; editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/SelectionWidget.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/SelectionWidget.java index 2fe33c069..93510d78f 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/SelectionWidget.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/SelectionWidget.java @@ -144,6 +144,7 @@ public void onWidgetSelectionItemClicked(@NonNull String selectedValue) { mListener.valueChanged(SelectionWidget.this); mEditText.setText(getKeyFromValue(selectedValue)); mEditText.requestFocus(); + isEdited = true; } private void hideSoftKey(@NonNull View focusedView) { diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/TextWidget.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/TextWidget.java index 4e8994718..59b2fe75e 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/TextWidget.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/TextWidget.java @@ -54,7 +54,7 @@ public View getView(@NonNull final ViewGroup viewGroup) { new ContextThemeWrapper(viewGroup.getContext(), R.style.Widget_Hyperwallet_TextInputEditText)); editText.setTextColor(viewGroup.getContext().getResources().getColor(R.color.regularColorSecondary)); editText.setEnabled(mField.isEditable()); - + isEdited = true; mTextInputLayout.setHint(mField.getLabel()); setIdFromFieldLabel(mTextInputLayout); setIdFromFieldName(editText); From 2a4ff312b952d9bc00280f3f102a89f27ac4aaf9 Mon Sep 17 00:00:00 2001 From: ssabeerahamed Date: Tue, 15 Dec 2020 12:39:05 +0530 Subject: [PATCH 04/33] DTSERWFOUR-210- update UI-SDK-Repo --- ...erMethodUpdateConfigurationRepository.java | 10 ----- ...thodUpdateConfigurationRepositoryImpl.java | 42 ------------------- 2 files changed, 52 deletions(-) diff --git a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepository.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepository.java index 1e0040dac..5a78eb5c3 100644 --- a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepository.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepository.java @@ -35,22 +35,12 @@ public interface TransferMethodUpdateConfigurationRepository { - void getKeys(@NonNull final LoadKeysCallback loadKeysCallback); - void getFields(@NonNull final String transferMethodType, @NonNull final LoadFieldsCallback loadFieldsCallback); - void refreshKeys(); void refreshFields(); - interface LoadKeysCallback { - - void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKey transferMethodConfigurationKey); - - void onError(@NonNull final Errors errors); - } - interface LoadFieldsCallback { void onFieldsLoaded(@Nullable final HyperwalletTransferMethodConfigurationField field); diff --git a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImpl.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImpl.java index 1bbfb956d..520c15e6b 100644 --- a/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImpl.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImpl.java @@ -69,34 +69,6 @@ Hyperwallet getHyperwallet() { return Hyperwallet.getDefault(); } - @VisibleForTesting - void getTransferMethodConfigurationKeyResult(final LoadKeysCallback loadKeysCallback) { - TransferMethodConfigurationKeysQuery query = new TransferMethodConfigurationKeysQuery(); - EspressoIdlingResource.increment(); - - getHyperwallet().retrieveTransferMethodConfigurationKeys(query, - new HyperwalletListener() { - @Override - public void onSuccess(@Nullable HyperwalletTransferMethodConfigurationKey result) { - mTransferMethodConfigurationKey = result; - loadKeysCallback.onKeysLoaded(mTransferMethodConfigurationKey); - EspressoIdlingResource.decrement(); - } - - @Override - public void onFailure(HyperwalletException exception) { - loadKeysCallback.onError(exception.getErrors()); - EspressoIdlingResource.decrement(); - } - - @Override - public Handler getHandler() { - return mHandler; - } - }); - } - - @VisibleForTesting void getTransferMethodConfigurationFieldResult( @NonNull final String transferMethodType, @@ -130,15 +102,6 @@ public Handler getHandler() { } - @Override - public synchronized void getKeys(@NonNull final LoadKeysCallback loadKeysCallback) { - if (mTransferMethodConfigurationKey == null) { - getTransferMethodConfigurationKeyResult(loadKeysCallback); - } else { - loadKeysCallback.onKeysLoaded(mTransferMethodConfigurationKey); - } - } - @Override public synchronized void getFields(@NonNull final String transferMethodType, @NonNull final LoadFieldsCallback loadFieldsCallback) { @@ -154,11 +117,6 @@ public synchronized void getFields(@NonNull final String transferMethodType, } } - @Override - public void refreshKeys() { - mTransferMethodConfigurationKey = null; - } - @Override public void refreshFields() { mFieldMap.clear(); From 0c2e207258da1ee7569c19e21745a938d04ed569 Mon Sep 17 00:00:00 2001 From: Rajkumar Date: Tue, 15 Dec 2020 14:32:01 +0530 Subject: [PATCH 05/33] DTSERWFOUR-211 - Fetch transfer method information and display for edits. --- .../ui/common/intent/HyperwalletIntent.java | 10 + transfermethodui/src/main/AndroidManifest.xml | 5 + .../HyperwalletTransferMethodUi.java | 18 + .../TransferMethodLocalBroadcast.java | 10 + .../view/UpdateTransferMethodActivity.java | 172 +++++ .../view/UpdateTransferMethodContract.java | 67 ++ .../view/UpdateTransferMethodFragment.java | 701 ++++++++++++++++++ .../view/UpdateTransferMethodPresenter.java | 108 +++ .../activity_update_transfer_method.xml | 49 ++ .../fragment_update_transfer_method.xml | 119 +++ 10 files changed, 1259 insertions(+) create mode 100644 transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodActivity.java create mode 100644 transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodContract.java create mode 100644 transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodFragment.java create mode 100644 transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodPresenter.java create mode 100644 transfermethodui/src/main/res/layout/activity_update_transfer_method.xml create mode 100644 transfermethodui/src/main/res/layout/fragment_update_transfer_method.xml diff --git a/commonui/src/main/java/com/hyperwallet/android/ui/common/intent/HyperwalletIntent.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/intent/HyperwalletIntent.java index d87c5d13d..992ddfb3f 100644 --- a/commonui/src/main/java/com/hyperwallet/android/ui/common/intent/HyperwalletIntent.java +++ b/commonui/src/main/java/com/hyperwallet/android/ui/common/intent/HyperwalletIntent.java @@ -65,6 +65,11 @@ private HyperwalletIntent() { */ public static final short SELECT_TRANSFER_SOURCE_REQUEST_CODE = 104; + /** + * Update Transfer method request code + */ + public static final short UPDATE_TRANSFER_METHOD_REQUEST_CODE = 105; + /** * SDK Broadcast payload error */ @@ -81,5 +86,10 @@ private HyperwalletIntent() { */ public static final String EXTRA_TRANSFER_METHOD_ADDED = "EXTRA_TRANSFER_METHOD_ADDED"; + /** + * Transfer method updated, extra activity parcelable transfer method payload + */ + public static final String EXTRA_TRANSFER_METHOD_UPDATED = "EXTRA_TRANSFER_METHOD_UPDATED"; + } diff --git a/transfermethodui/src/main/AndroidManifest.xml b/transfermethodui/src/main/AndroidManifest.xml index 2a97d4dee..d46f47fb2 100644 --- a/transfermethodui/src/main/AndroidManifest.xml +++ b/transfermethodui/src/main/AndroidManifest.xml @@ -12,6 +12,11 @@ android:theme="@style/AppTheme.NoActionBar" android:windowSoftInputMode="adjustResize"/> + + true screen will be locked to Portrait mode; + * otherwise false screen will follow whatever the + * device orientation is directed. + * @return an Intent with the data necessary to launch the {@link UpdateTransferMethodActivity} + */ + public Intent getIntentUpdateTransferMethodActivity(@NonNull final Context context, + @NonNull final String transferMethodToken, final boolean lockScreenToPortrait) { + Intent intent = new Intent(context, UpdateTransferMethodActivity.class); + intent.putExtra(EXTRA_TRANSFER_METHOD_TOKEN, transferMethodToken); + intent.putExtra(AddTransferMethodActivity.EXTRA_LOCK_SCREEN_ORIENTATION_TO_PORTRAIT, lockScreenToPortrait); + return intent; + } + public static void clearInstance() { sInstance = null; Hyperwallet.clearInstance(); diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodLocalBroadcast.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodLocalBroadcast.java index f0d88bca0..5d703d328 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodLocalBroadcast.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodLocalBroadcast.java @@ -19,6 +19,7 @@ import static com.hyperwallet.android.ui.common.intent.HyperwalletIntent.HYPERWALLET_LOCAL_BROADCAST_PAYLOAD_KEY; import static com.hyperwallet.android.ui.transfermethod.TransferMethodLocalBroadcast.TransferMethodLocalBroadcastAction.ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED; import static com.hyperwallet.android.ui.transfermethod.TransferMethodLocalBroadcast.TransferMethodLocalBroadcastAction.ACTION_HYPERWALLET_TRANSFER_METHOD_DEACTIVATED; +import static com.hyperwallet.android.ui.transfermethod.TransferMethodLocalBroadcast.TransferMethodLocalBroadcastAction.ACTION_HYPERWALLET_TRANSFER_METHOD_UPDATED; import android.content.Intent; import android.os.Parcelable; @@ -40,6 +41,12 @@ public static Intent createBroadcastIntentTransferMethodAdded( ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED); } + public static Intent createBroadcastIntentTransferMethodUpdated( + @NonNull final TransferMethod transferMethod) { + return createBroadcastIntent(transferMethod, + ACTION_HYPERWALLET_TRANSFER_METHOD_UPDATED); + } + public static Intent createBroadcastIntentTransferMethodDeactivated( @NonNull final StatusTransition StatusTransition) { return createBroadcastIntent(StatusTransition, @@ -57,6 +64,7 @@ private static Intent createBroadcastIntent(@NonNull final Parcelable parcelable @Retention(RetentionPolicy.SOURCE) @StringDef({ ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED, + ACTION_HYPERWALLET_TRANSFER_METHOD_UPDATED, ACTION_HYPERWALLET_TRANSFER_METHOD_DEACTIVATED }) public @interface TransferMethodLocalBroadcastActionType { @@ -69,5 +77,7 @@ private TransferMethodLocalBroadcastAction() {} "ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED"; public static final String ACTION_HYPERWALLET_TRANSFER_METHOD_DEACTIVATED = "ACTION_HYPERWALLET_TRANSFER_METHOD_DEACTIVATED"; + public static final String ACTION_HYPERWALLET_TRANSFER_METHOD_UPDATED = + "ACTION_HYPERWALLET_TRANSFER_METHOD_UPDATED"; } } diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodActivity.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodActivity.java new file mode 100644 index 000000000..c3f3a0694 --- /dev/null +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodActivity.java @@ -0,0 +1,172 @@ +package com.hyperwallet.android.ui.transfermethod.view; + +import android.content.pm.ActivityInfo; +import android.os.Bundle; +import android.view.View; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.FragmentManager; + +import com.google.android.material.appbar.CollapsingToolbarLayout; +import com.hyperwallet.android.model.Error; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.util.PageGroups; +import com.hyperwallet.android.ui.common.view.ActivityUtils; +import com.hyperwallet.android.ui.common.view.TransferMethodUtils; +import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; + +import java.util.List; + +public class UpdateTransferMethodActivity extends AppCompatActivity implements + WidgetSelectionDialogFragment.WidgetSelectionItemListener, + UpdateTransferMethodFragment.OnUpdateTransferMethodNetworkErrorCallback, + UpdateTransferMethodFragment.OnLoadTransferMethodConfigurationFieldsNetworkErrorCallback, + OnNetworkErrorCallback, WidgetDateDialogFragment.OnSelectedDateCallback { + + public static final String TAG = "transfer-method:update:collect-transfer-method-information"; + + public static final String EXTRA_TRANSFER_METHOD_TOKEN = "EXTRA_TRANSFER_METHOD_TOKEN"; + private static final String ARGUMENT_RETRY_ACTION = "ARGUMENT_RETRY_ACTION"; + public static final String EXTRA_LOCK_SCREEN_ORIENTATION_TO_PORTRAIT = "EXTRA_LOCK_SCREEN_ORIENTATION_TO_PORTRAIT"; + private static final short RETRY_SHOW_ERROR_UPDATE_TRANSFER_METHOD = 100; + private static final short RETRY_SHOW_ERROR_LOAD_TMC_FIELDS = 101; + + private short mRetryCode; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_update_transfer_method); + + getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); +// TODO: Set Title +// getSupportActionBar().setTitle(TransferMethodUtils.getTransferMethodName(this, +// getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_TYPE))); + CollapsingToolbarLayout collapsingToolbar = findViewById(R.id.collapsing_toolbar); + int titleStyleCollapse = TransferMethodUtils.getAdjustCollapseTitleStyle(getTitle().toString()); + collapsingToolbar.setCollapsedTitleTextAppearance(titleStyleCollapse); + int titleStyleExpanded = TransferMethodUtils.getAdjustExpandTitleStyle(getTitle().toString()); + collapsingToolbar.setExpandedTitleTextAppearance(titleStyleExpanded); + + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + if (getIntent().getBooleanExtra(EXTRA_LOCK_SCREEN_ORIENTATION_TO_PORTRAIT, false)) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + if (savedInstanceState == null) { + ActivityUtils.initFragment(this, UpdateTransferMethodFragment.newInstance( + getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_TOKEN) + ), R.id.update_transfer_method_fragment); + } else { + mRetryCode = savedInstanceState.getShort(ARGUMENT_RETRY_ACTION); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + outState.putShort(ARGUMENT_RETRY_ACTION, mRetryCode); + super.onSaveInstanceState(outState); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + if (savedInstanceState != null) { + mRetryCode = savedInstanceState.getShort(ARGUMENT_RETRY_ACTION); + } + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } + + @Override + public void onBackPressed() { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimaryDark)); + getWindow().getDecorView().setSystemUiVisibility(0); + super.onBackPressed(); + } + + @Override + public void retry() { + UpdateTransferMethodFragment fragment = getUpdateTransferFragment(); + switch (mRetryCode) { + case RETRY_SHOW_ERROR_UPDATE_TRANSFER_METHOD: + fragment.retryUpdateTransferMethod(); + break; + case RETRY_SHOW_ERROR_LOAD_TMC_FIELDS: + fragment.reloadTransferMethodConfigurationFields(); + break; + default: // no default action + } + } + + private UpdateTransferMethodFragment getUpdateTransferFragment() { + FragmentManager fragmentManager = getSupportFragmentManager(); + UpdateTransferMethodFragment fragment = (UpdateTransferMethodFragment) + fragmentManager.findFragmentById(R.id.update_transfer_method_fragment); + + if (fragment == null) { + fragment = UpdateTransferMethodFragment.newInstance( + getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_TOKEN) + ); + } + return fragment; + } + + @Override + public void showErrorsLoadTransferMethodConfigurationFields(@NonNull List errors) { + mRetryCode = RETRY_SHOW_ERROR_LOAD_TMC_FIELDS; + ActivityUtils.showError(this, TAG, PageGroups.TRANSFER_METHOD, errors); + } + + @Override + public void showErrorsUpdateTransferMethod(@NonNull List errors) { + mRetryCode = RETRY_SHOW_ERROR_UPDATE_TRANSFER_METHOD; + ActivityUtils.showError(this, TAG, PageGroups.TRANSFER_METHOD, errors); + } + + @Override + public void setSelectedDateField(@NonNull String fieldName, String selectedValue) { + FragmentManager fragmentManager = getSupportFragmentManager(); + UpdateTransferMethodFragment updateTransferMethodFragment = + (UpdateTransferMethodFragment) fragmentManager.findFragmentById(R.id.update_transfer_method_fragment); + if (updateTransferMethodFragment != null) { + updateTransferMethodFragment.onDateSelected(selectedValue, fieldName); + } + } + + @Override + public void onWidgetSelectionItemClicked(@NonNull String selectedValue, @NonNull String fieldName) { + FragmentManager fragmentManager = getSupportFragmentManager(); + UpdateTransferMethodFragment updateTransferMethodFragment = + (UpdateTransferMethodFragment) fragmentManager.findFragmentById(R.id.update_transfer_method_fragment); + updateTransferMethodFragment.onWidgetSelectionItemClicked(selectedValue, fieldName); + + WidgetSelectionDialogFragment widgetSelectionDialogFragment = + (WidgetSelectionDialogFragment) fragmentManager.findFragmentById(android.R.id.content); + widgetSelectionDialogFragment.dismiss(); + getSupportFragmentManager().popBackStack(WidgetSelectionDialogFragment.TAG, + FragmentManager.POP_BACK_STACK_INCLUSIVE); + } +} diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodContract.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodContract.java new file mode 100644 index 000000000..1dcc66cea --- /dev/null +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodContract.java @@ -0,0 +1,67 @@ +package com.hyperwallet.android.ui.transfermethod.view; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.hyperwallet.android.model.Error; +import com.hyperwallet.android.model.graphql.Fee; +import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; +import com.hyperwallet.android.model.graphql.ProcessingTime; +import com.hyperwallet.android.model.graphql.field.FieldGroup; +import com.hyperwallet.android.model.transfermethod.TransferMethod; + +import java.util.List; +import java.util.Map; + +/** + * View and Presenter Contract for Updating Transfer Method + */ +public class UpdateTransferMethodContract { + + interface View { + + void notifyTransferMethodUpdated(@NonNull final TransferMethod transferMethod); + + void showErrorUpdateTransferMethod(@NonNull final List errors); + + void showErrorLoadTransferMethodConfigurationFields(@NonNull final List errors); + + void showTransferMethodFields(@NonNull final List fields); + + void showTransferMethodFields(@NonNull final HyperwalletTransferMethodConfigurationField field); + + void showTransactionInformation(@NonNull final List fees, + @Nullable final ProcessingTime processingTime); + + void showCreateButtonProgressBar(); + + void hideCreateButtonProgressBar(); + + void showProgressBar(); + + void hideProgressBar(); + + void showInputErrors(@NonNull final List errors); + + /** + * Check the state of a View + * + * @return true when View is added to Container + */ + boolean isActive(); + + void retryUpdateTransferMethod(); + + void reloadTransferMethodConfigurationFields(); + } + + interface Presenter { + + void updateTransferMethod(@NonNull TransferMethod transferMethod); + + void loadTransferMethodConfigurationFields(boolean forceUpdate, @NonNull final String transferMethodType); + + void handleUnmappedFieldError(@NonNull final Map fieldSet, + @NonNull final List errors); + } +} diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodFragment.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodFragment.java new file mode 100644 index 000000000..b97bec733 --- /dev/null +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodFragment.java @@ -0,0 +1,701 @@ +package com.hyperwallet.android.ui.transfermethod.view; + +import static com.hyperwallet.android.model.transfermethod.TransferMethod.TransferMethodFields.TYPE; +import static com.hyperwallet.android.model.transfermethod.TransferMethod.TransferMethodTypes.BANK_ACCOUNT; +import static com.hyperwallet.android.model.transfermethod.TransferMethod.TransferMethodTypes.BANK_CARD; +import static com.hyperwallet.android.model.transfermethod.TransferMethod.TransferMethodTypes.PAPER_CHECK; +import static com.hyperwallet.android.model.transfermethod.TransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT; +import static com.hyperwallet.android.model.transfermethod.TransferMethod.TransferMethodTypes.VENMO_ACCOUNT; +import static com.hyperwallet.android.model.transfermethod.TransferMethod.TransferMethodTypes.WIRE_ACCOUNT; +import static com.hyperwallet.android.ui.common.intent.HyperwalletIntent.EXTRA_TRANSFER_METHOD_UPDATED; +import static com.hyperwallet.android.ui.transfermethod.TransferMethodLocalBroadcast.TransferMethodLocalBroadcastAction.ACTION_HYPERWALLET_TRANSFER_METHOD_UPDATED; +import static com.hyperwallet.android.ui.transfermethod.view.FeeFormatter.isFeeAvailable; +import static com.hyperwallet.android.ui.transfermethod.view.FeeFormatter.isProcessingTimeAvailable; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.widget.NestedScrollView; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentTransaction; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.model.Error; +import com.hyperwallet.android.model.graphql.Fee; +import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; +import com.hyperwallet.android.model.graphql.ProcessingTime; +import com.hyperwallet.android.model.graphql.field.Field; +import com.hyperwallet.android.model.graphql.field.FieldGroup; +import com.hyperwallet.android.model.transfermethod.BankAccount; +import com.hyperwallet.android.model.transfermethod.BankCard; +import com.hyperwallet.android.model.transfermethod.PaperCheck; +import com.hyperwallet.android.model.transfermethod.PayPalAccount; +import com.hyperwallet.android.model.transfermethod.TransferMethod; +import com.hyperwallet.android.model.transfermethod.VenmoAccount; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.insight.HyperwalletInsight; +import com.hyperwallet.android.ui.common.util.ErrorTypes; +import com.hyperwallet.android.ui.common.util.PageGroups; +import com.hyperwallet.android.ui.transfermethod.TransferMethodLocalBroadcast; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; +import com.hyperwallet.android.ui.transfermethod.view.widget.AbstractWidget; +import com.hyperwallet.android.ui.transfermethod.view.widget.DateChangedListener; +import com.hyperwallet.android.ui.transfermethod.view.widget.DateWidget; +import com.hyperwallet.android.ui.transfermethod.view.widget.WidgetEventListener; +import com.hyperwallet.android.ui.transfermethod.view.widget.WidgetFactory; +import com.hyperwallet.android.ui.transfermethod.view.widget.WidgetInputState; + +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.TreeMap; + +public class UpdateTransferMethodFragment extends Fragment implements WidgetEventListener, + UpdateTransferMethodContract.View { + + + public static final String TAG = UpdateTransferMethodActivity.TAG; + + private static final String ARGUMENT_TRANSFER_METHOD_TOKEN = "ARGUMENT_TRANSFER_METHOD_TOKEN"; + private static final String ARGUMENT_SHOW_CREATE_PROGRESS_BAR = "ARGUMENT_SHOW_CREATE_PROGRESS_BAR"; + private static final String ARGUMENT_WIDGET_STATE_MAP = "ARGUMENT_WIDGET_STATE_MAP"; + private static final boolean FORCE_UPDATE = false; + private View mCreateButtonProgressBar; + private Button mUpdateTransferMethodButton; + private ViewGroup mDynamicContainer; + private NestedScrollView mNestedScrollView; + private OnUpdateTransferMethodNetworkErrorCallback mOnUpdateTransferMethodNetworkErrorCallback; + private OnLoadTransferMethodConfigurationFieldsNetworkErrorCallback + mOnLoadTransferMethodConfigurationFieldsNetworkErrorCallback; + private UpdateTransferMethodContract.Presenter mPresenter; + private View mProgressBar; + private boolean mUpdateButtonProgressBar; + private String mTransferMethodType; + private TransferMethod mTransferMethod; + private String mTransferMethodToken; + private HashMap mWidgetInputStateHashMap; + + /** + * Please do not use this to have instance of UpdateTransferMethodFragment this is reserved for android framework + */ + public UpdateTransferMethodFragment() { + } + + /** + * Creates new instance of UpdateTransferMethodFragment this is the proper initialization of this class + * since the default constructor is reserved for android framework when lifecycle is triggered. + * The parameters in {@link UpdateTransferMethodFragment#newInstance(String)} is mandatory + * and should be supplied with correct data or this fragment will not initialize properly. + * + * @param transferMethodToken the country selected when creating transfer method + */ + public static UpdateTransferMethodFragment newInstance(@NonNull String transferMethodToken) { + UpdateTransferMethodFragment updateTransferMethodFragment = new UpdateTransferMethodFragment(); + Bundle arguments = new Bundle(); + + updateTransferMethodFragment.mTransferMethodToken = transferMethodToken; + updateTransferMethodFragment.mWidgetInputStateHashMap = new HashMap<>(1); + updateTransferMethodFragment.mTransferMethod = null; + arguments.putParcelable(ARGUMENT_TRANSFER_METHOD_TOKEN, updateTransferMethodFragment.mTransferMethod); + arguments.putSerializable(ARGUMENT_WIDGET_STATE_MAP, updateTransferMethodFragment.mWidgetInputStateHashMap); + updateTransferMethodFragment.setArguments(arguments); + + return updateTransferMethodFragment; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + + try { + mOnUpdateTransferMethodNetworkErrorCallback = (OnUpdateTransferMethodNetworkErrorCallback) context; + } catch (ClassCastException e) { + throw new ClassCastException(getActivity().toString() + " must implement " + + OnUpdateTransferMethodNetworkErrorCallback.class.getCanonicalName()); + } + + try { + mOnLoadTransferMethodConfigurationFieldsNetworkErrorCallback = + (OnLoadTransferMethodConfigurationFieldsNetworkErrorCallback) context; + } catch (ClassCastException e) { + throw new ClassCastException(getActivity().toString() + " must implement " + + OnLoadTransferMethodConfigurationFieldsNetworkErrorCallback.class.getCanonicalName()); + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + } + + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_update_transfer_method, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + mDynamicContainer = view.findViewById(R.id.update_transfer_method_dynamic_container); + mNestedScrollView = view.findViewById(R.id.update_transfer_method_scroll_view); + + mCreateButtonProgressBar = view.findViewById(R.id.update_transfer_method_progress_bar); + mProgressBar = view.findViewById(R.id.update_transfer_method_progress_bar_layout); + mUpdateTransferMethodButton = view.findViewById(R.id.update_transfer_method_button); + + mUpdateTransferMethodButton.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); + mUpdateTransferMethodButton.setTextColor(getResources().getColor(R.color.regularColorPrimary)); + mUpdateTransferMethodButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + HyperwalletInsight.getInstance().trackClick(requireContext(), + TAG, PageGroups.TRANSFER_METHOD, + HyperwalletInsight.LINK_SELECT_TRANSFER_METHOD_CREATE, + new HyperwalletInsight.TransferMethodParamsBuilder() +// .country(mCountry) +// .currency(mCurrency) + .type(mTransferMethodType) +// .profileType(mTransferMethodProfileType) + .build()); + + triggerSubmit(); + } + }); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + TransferMethodRepositoryFactory factory = TransferMethodRepositoryFactory.getInstance(); + mPresenter = new UpdateTransferMethodPresenter(this, + factory.getUpdateTransferMethodConfigurationRepository(), + factory.getTransferMethodRepository()); + } + + @Override + public void onViewStateRestored(@Nullable Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + + if (savedInstanceState != null) { + mWidgetInputStateHashMap = (HashMap) savedInstanceState.getSerializable(ARGUMENT_WIDGET_STATE_MAP); + mTransferMethodToken = savedInstanceState.getString(ARGUMENT_TRANSFER_METHOD_TOKEN); + mUpdateButtonProgressBar = savedInstanceState.getBoolean(ARGUMENT_SHOW_CREATE_PROGRESS_BAR); + mTransferMethod = savedInstanceState.getParcelable(ARGUMENT_TRANSFER_METHOD_TOKEN); + } else { // same as UpdateTransferMethodFragment#newInstance + mWidgetInputStateHashMap = (HashMap) getArguments().getSerializable(ARGUMENT_WIDGET_STATE_MAP); + mTransferMethodToken = getArguments().getString(ARGUMENT_TRANSFER_METHOD_TOKEN); + } + } + + @Override + public void onResume() { + super.onResume(); + mPresenter.loadTransferMethodConfigurationFields(FORCE_UPDATE, mTransferMethodType); + } + + @Override + public void showErrorUpdateTransferMethod(@NonNull final List errors) { + mOnUpdateTransferMethodNetworkErrorCallback.showErrorsUpdateTransferMethod(errors); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + outState.putSerializable(ARGUMENT_WIDGET_STATE_MAP, mWidgetInputStateHashMap); + outState.putString(ARGUMENT_TRANSFER_METHOD_TOKEN, mTransferMethodToken); + outState.putBoolean(ARGUMENT_SHOW_CREATE_PROGRESS_BAR, mUpdateButtonProgressBar); + super.onSaveInstanceState(outState); + } + + private void triggerSubmit() { + hideSoftKeys(); + if (performValidation()) { + switch (mTransferMethodType) { + case BANK_ACCOUNT: + mTransferMethod = new BankAccount.Builder() +// .transferMethodCountry(mCountry) +// .transferMethodCurrency(mCurrency) + .build(); + break; + case BANK_CARD: + mTransferMethod = new BankCard.Builder() +// transferMethodCountry(mCountry).transferMethodCurrency(mCurrency) + .build(); + break; + case PAYPAL_ACCOUNT: + mTransferMethod = new PayPalAccount.Builder() +// .transferMethodCountry(mCountry) +// .transferMethodCurrency(mCurrency) + .build(); + break; + case WIRE_ACCOUNT: + mTransferMethod = new BankAccount.Builder() +// .transferMethodCountry(mCountry) +// .transferMethodCurrency(mCurrency) + .transferMethodType(WIRE_ACCOUNT) + .build(); + break; + case VENMO_ACCOUNT: + mTransferMethod = new VenmoAccount.Builder() +// .transferMethodCountry(mCountry) +// .transferMethodCurrency(mCurrency) + .build(); + break; + case PAPER_CHECK: + mTransferMethod = new PaperCheck.Builder() +// .transferMethodCountry(mCountry) +// .transferMethodCurrency(mCurrency) + .build(); + break; + default: + mTransferMethod = new TransferMethod(); +// mTransferMethod.setField(TRANSFER_METHOD_COUNTRY, mCountry); +// mTransferMethod.setField(TRANSFER_METHOD_CURRENCY, mCurrency); + mTransferMethod.setField(TYPE, mTransferMethodType); + } + + for (int i = 0; i < mDynamicContainer.getChildCount(); i++) { + View view = mDynamicContainer.getChildAt(i); + if (view.getTag() instanceof AbstractWidget) { + AbstractWidget widget = (AbstractWidget) view.getTag(); + mTransferMethod.setField(widget.getName(), widget.getValue()); + } + } + + mPresenter.updateTransferMethod(mTransferMethod); + } + } + + private void hideSoftKeys() { + View view = requireActivity().getCurrentFocus(); + + if (view != null) { + view.clearFocus(); + InputMethodManager inputMethodManager = (InputMethodManager) view.getContext().getSystemService( + Activity.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + + + /** + * Use this to perform validation on an entire form, typically used during form submission. + * + * @return true if the form is valid + */ + private boolean performValidation() { + boolean containsInvalidWidget = false; + + // this is added since some phones triggers the create button but the widgets are not yet initialized + boolean hasWidget = false; + Resources resources = requireContext().getResources(); + int pixels = (int) (resources.getDimension(R.dimen.negative_padding) * resources.getDisplayMetrics().density); + + for (int i = 0; i < mDynamicContainer.getChildCount(); i++) { + View currentView = mDynamicContainer.getChildAt(i); + if (currentView.getTag() instanceof AbstractWidget) { + hasWidget = true; + + AbstractWidget widget = (AbstractWidget) currentView.getTag(); + WidgetInputState widgetInputState = mWidgetInputStateHashMap.get(widget.getName()); + widgetInputState.setValue(widget.getValue()); + + if (!isWidgetItemValid(widget) && !containsInvalidWidget) { + containsInvalidWidget = true; + mNestedScrollView.smoothScrollTo(0, currentView.getTop() - pixels); + } + } + } + return hasWidget && !containsInvalidWidget; + } + + /** + * Use this to perform validation on a single widget item, typically used while the user is inputting data. + * + * @param widget the widget to validate + * @return true if the input is valid + */ + private boolean isWidgetItemValid(@NonNull final AbstractWidget widget) { + boolean valid = true; + Context context = requireContext(); + + WidgetInputState widgetInputState = mWidgetInputStateHashMap.get(widget.getName()); + widgetInputState.setValue(widget.getValue()); + if (widget.isValid()) { + if (!widgetInputState.hasApiError()) { + widgetInputState.setErrorMessage(null); + widget.showValidationError(null); + } + } else { + HyperwalletInsight.getInstance().trackError(context, + TAG, PageGroups.TRANSFER_METHOD, + new HyperwalletInsight.ErrorParamsBuilder() + .message(widget.getErrorMessage()) + .fieldName(widget.getName()) + .type(ErrorTypes.FORM_ERROR) + .addAll(new HyperwalletInsight.TransferMethodParamsBuilder() +// .country(mCountry) +// .currency(mCurrency) + .type(mTransferMethodType) +// .profileType(mTransferMethodProfileType) + .build()) + .build()); + + valid = false; + widget.showValidationError(null); + widgetInputState.setErrorMessage(null); + widget.showValidationError(widget.getErrorMessage()); + widgetInputState.setErrorMessage(widget.getErrorMessage()); + widgetInputState.setHasApiError(false); + } + return valid; + } + + @Override + public void notifyTransferMethodUpdated(@NonNull TransferMethod transferMethod) { + HyperwalletInsight.getInstance().trackImpression(requireContext(), + TAG, PageGroups.TRANSFER_METHOD, + new HyperwalletInsight.TransferMethodParamsBuilder() + .goal(HyperwalletInsight.TRANSFER_METHOD_GOAL) +// .country(mCountry) +// .currency(mCurrency) + .type(mTransferMethodType) +// .profileType(mTransferMethodProfileType) + .build()); + + Intent intent = TransferMethodLocalBroadcast.createBroadcastIntentTransferMethodUpdated( + transferMethod); + LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); + + Intent activityResult = new Intent(); + activityResult.setAction(ACTION_HYPERWALLET_TRANSFER_METHOD_UPDATED); + activityResult.putExtra(EXTRA_TRANSFER_METHOD_UPDATED, transferMethod); + getActivity().setResult(Activity.RESULT_OK, activityResult); + getActivity().finish(); + } + + @Override + public void showErrorLoadTransferMethodConfigurationFields(@NonNull List errors) { + mOnLoadTransferMethodConfigurationFieldsNetworkErrorCallback.showErrorsLoadTransferMethodConfigurationFields( + errors); + } + + @Override + public void showTransferMethodFields(@NonNull List fields) { + mDynamicContainer.removeAllViews(); + + try { +// Locale locale = new Locale.Builder().setRegion(mCountry).build(); + Locale locale = Locale.getDefault(); + + // group + for (FieldGroup group : fields) { + View sectionHeader = LayoutInflater.from(mDynamicContainer.getContext()) + .inflate(R.layout.item_widget_section_header, mDynamicContainer, false); + TextView sectionTitle = sectionHeader.findViewById(R.id.section_header_title); + sectionTitle.setText(getSectionHeaderText(group, locale)); + sectionHeader.setId(View.generateViewId()); + mDynamicContainer.addView(sectionHeader); + + // group fields + for (final Field field : group.getFields()) { + AbstractWidget widget = WidgetFactory + .newWidget(field, this, mWidgetInputStateHashMap.containsKey(field.getName()) ? + mWidgetInputStateHashMap.get(field.getName()).getValue() : field.getValue(), + mUpdateTransferMethodButton); + if (mWidgetInputStateHashMap.isEmpty() || !mWidgetInputStateHashMap.containsKey(widget.getName())) { + mWidgetInputStateHashMap.put(widget.getName(), widget.getWidgetInputState()); + } + + View widgetView = widget.getView(mDynamicContainer); + widgetView.setTag(widget); + widgetView.setId(View.generateViewId()); + final String error = mWidgetInputStateHashMap.get(widget.getName()).getErrorMessage(); + widget.showValidationError(error); + mDynamicContainer.addView(widgetView); + } + } + + HyperwalletInsight.getInstance().trackImpression(requireContext(), + TAG, PageGroups.TRANSFER_METHOD, + new HyperwalletInsight.TransferMethodParamsBuilder() +// .country(mCountry) +// .currency(mCurrency) + .type(mTransferMethodType) +// .profileType(mTransferMethodProfileType) + .build()); + + if (mUpdateButtonProgressBar) { + setVisibleAndDisableFields(); + } + } catch (HyperwalletException e) { + throw new IllegalStateException("Widget initialization error: " + e.getMessage()); + } + } + + private String getSectionHeaderText(@NonNull final FieldGroup group, @NonNull final Locale locale) { + if (FieldGroup.GroupTypes.ACCOUNT_INFORMATION.equals(group.getGroupName())) { + return requireContext().getString(R.string.account_information, + locale.getDisplayName().toUpperCase(), "USD"); +// locale.getDisplayName().toUpperCase(), mCurrency); + } + + return requireContext().getString(requireContext().getResources() + .getIdentifier(group.getGroupName().toLowerCase(Locale.ROOT), "string", + requireContext().getPackageName())); + } + + @Override + public void showTransactionInformation(@NonNull List fees, + @Nullable ProcessingTime processingTime) { + View header = getView().findViewById(R.id.update_transfer_method_static_container_header); + View container = getView().findViewById(R.id.update_transfer_method_static_container); + TextView feeAndProcessingTime = getView().findViewById(R.id.update_transfer_method_information); + + if (isFeeAvailable(fees) && isProcessingTimeAvailable(processingTime)) { + String formattedFee = FeeFormatter.getFormattedFee(header.getContext(), fees); + feeAndProcessingTime.setVisibility(View.VISIBLE); + feeAndProcessingTime.setText( + feeAndProcessingTime.getContext().getString(R.string.feeAndProcessingTimeInformation, formattedFee, + processingTime.getValue())); + } else if (isFeeAvailable(fees) && !isProcessingTimeAvailable(processingTime)) { + String formattedFee = FeeFormatter.getFormattedFee(header.getContext(), fees); + feeAndProcessingTime.setVisibility(View.VISIBLE); + feeAndProcessingTime.setText( + feeAndProcessingTime.getContext().getString(R.string.feeInformation, formattedFee)); + } else if (isProcessingTimeAvailable(processingTime) && !isFeeAvailable(fees)) { + feeAndProcessingTime.setVisibility(View.VISIBLE); + feeAndProcessingTime.setText(processingTime.getValue()); + } else { + feeAndProcessingTime.setVisibility(View.GONE); + } + + if (feeAndProcessingTime.getVisibility() == View.VISIBLE) { + header.setVisibility(View.VISIBLE); + container.setVisibility(View.VISIBLE); + } else { + header.setVisibility(View.GONE); + container.setVisibility(View.GONE); + } + } + + @Override + public void showTransferMethodFields(@NonNull HyperwalletTransferMethodConfigurationField field) { + + } + + @Override + public void showCreateButtonProgressBar() { + mUpdateButtonProgressBar = true; + setVisibleAndDisableFields(); + } + + private void setVisibleAndDisableFields() { + getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); + mCreateButtonProgressBar.setVisibility(View.VISIBLE); + mUpdateTransferMethodButton.setBackgroundColor(getResources().getColor(R.color.colorSecondaryDark)); + } + + @Override + public void hideCreateButtonProgressBar() { + mUpdateButtonProgressBar = false; + getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); + mCreateButtonProgressBar.setVisibility(View.GONE); + mUpdateTransferMethodButton.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); + mUpdateTransferMethodButton.setTextColor(getResources().getColor(R.color.regularColorPrimary)); + } + + @Override + public void showProgressBar() { + mProgressBar.setVisibility(View.VISIBLE); + } + + @Override + public void hideProgressBar() { + mProgressBar.setVisibility(View.GONE); + mUpdateTransferMethodButton.setVisibility(View.VISIBLE); + } + + @Override + public void showInputErrors(@NonNull List errors) { + boolean focusSet = false; + Context context = requireContext(); + Resources resources = context.getResources(); + int pixels = (int) (resources.getDimension(R.dimen.negative_padding) * resources.getDisplayMetrics().density); + + for (Error error : errors) { + for (int i = 0; i < mDynamicContainer.getChildCount(); i++) { + View view = mDynamicContainer.getChildAt(i); + if (view.getTag() instanceof AbstractWidget) { + AbstractWidget widget = (AbstractWidget) view.getTag(); + WidgetInputState widgetInputState = mWidgetInputStateHashMap.get(widget.getName()); + if (widget.getName().equals(error.getFieldName())) { + if (!focusSet) { + mNestedScrollView.smoothScrollTo(0, view.getTop() - pixels); + focusSet = true; + } + HyperwalletInsight.getInstance().trackError(context, + TAG, PageGroups.TRANSFER_METHOD, + new HyperwalletInsight.ErrorParamsBuilder() + .code(error.getCode()) + .message(error.getMessage()) + .fieldName(error.getFieldName()) + .type(ErrorTypes.API_ERROR) + .build()); + + widget.showValidationError(null); + widgetInputState.setErrorMessage(null); + widget.showValidationError(error.getMessage()); + widgetInputState.setErrorMessage(error.getMessage()); + widgetInputState.setHasApiError(true); + } else { + widget.showValidationError(null); + widgetInputState.setErrorMessage(null); + } + } + } + } + + mPresenter.handleUnmappedFieldError(mWidgetInputStateHashMap, errors); + } + + @Override + public boolean isActive() { + return isAdded(); + } + + @Override + public void retryUpdateTransferMethod() { + mPresenter.updateTransferMethod(mTransferMethod); + } + + @Override + public void reloadTransferMethodConfigurationFields() { + mPresenter.loadTransferMethodConfigurationFields(FORCE_UPDATE, mTransferMethodType); + } + + @Override + public void valueChanged(@NonNull AbstractWidget widget) { + isWidgetItemValid(widget); + } + + @Override + public boolean isWidgetSelectionFragmentDialogOpen() { + return getFragmentManager().findFragmentByTag(WidgetSelectionDialogFragment.TAG) != null; + } + + @Override + public void openWidgetSelectionFragmentDialog(@NonNull TreeMap nameValueMap, + @NonNull String selectedName, @NonNull String fieldLabel, @NonNull String fieldName) { + String selectedLabel = selectedName; + if (TextUtils.isEmpty(selectedLabel)) { + selectedLabel = mWidgetInputStateHashMap.get(fieldName).getSelectedName(); + } else { + mWidgetInputStateHashMap.get(fieldName).setSelectedName(selectedLabel); + } + + if (!isWidgetSelectionFragmentDialogOpen()) { + WidgetSelectionDialogFragment widgetSelectionDialogFragment = WidgetSelectionDialogFragment + .newInstance(nameValueMap, selectedLabel, fieldLabel, fieldName); + + FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); + fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); + fragmentTransaction.replace(android.R.id.content, widgetSelectionDialogFragment, + WidgetSelectionDialogFragment.TAG); + fragmentTransaction.addToBackStack(WidgetSelectionDialogFragment.TAG); + fragmentTransaction.commit(); + } + } + + @Override + public void widgetFocused(@NonNull String fieldName) { + WidgetInputState widgetInputState = mWidgetInputStateHashMap.get(fieldName); + widgetInputState.setHasFocused(true); + } + + @Override + public void saveTextChanged(@NonNull String fieldName, @NonNull String value) { + WidgetInputState inputState = mWidgetInputStateHashMap.get(fieldName); + if (inputState.hasApiError()) { + String oldValue = inputState.getValue(); + if (!TextUtils.isEmpty(oldValue) && !oldValue.equals(value)) { + inputState.setHasApiError(false); + } + } + inputState.setValue(value); + } + + void onWidgetSelectionItemClicked(@NonNull final String selectedValue, @NonNull final String fieldName) { + for (int i = 0; i < mDynamicContainer.getChildCount(); i++) { + View view = mDynamicContainer.getChildAt(i); + if (view.getTag() instanceof WidgetSelectionDialogFragment.WidgetSelectionItemType) { + AbstractWidget widget = (AbstractWidget) view.getTag(); + if (fieldName.equals(widget.getName())) { + ((WidgetSelectionDialogFragment.WidgetSelectionItemType) view.getTag()) + .onWidgetSelectionItemClicked(selectedValue); + return; + } + } + } + } + + @Override + public void openWidgetDateDialog(@Nullable String date, @NonNull String fieldName) { + if (getFragmentManager() != null) { + WidgetDateDialogFragment dateDialogFragment = (WidgetDateDialogFragment) + getFragmentManager().findFragmentByTag(WidgetDateDialogFragment.TAG); + + if (dateDialogFragment == null) { + dateDialogFragment = WidgetDateDialogFragment.newInstance(date, fieldName); + } + + if (!dateDialogFragment.isAdded()) { + dateDialogFragment.show(getFragmentManager()); + } + } + } + + void onDateSelected(@NonNull final String selectedValue, @NonNull final String fieldName) { + for (int i = 0; i < mDynamicContainer.getChildCount(); i++) { + View view = mDynamicContainer.getChildAt(i); + if (view.getTag() instanceof DateWidget) { + AbstractWidget widget = (AbstractWidget) view.getTag(); + if (fieldName.equals(widget.getName()) && widget instanceof DateChangedListener) { + ((DateChangedListener) view.getTag()).onUpdate(selectedValue); + return; + } + } + } + } + + interface OnLoadTransferMethodConfigurationFieldsNetworkErrorCallback { + void showErrorsLoadTransferMethodConfigurationFields(@NonNull final List errors); + } + + interface OnUpdateTransferMethodNetworkErrorCallback { + void showErrorsUpdateTransferMethod(@NonNull final List errors); + } +} diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodPresenter.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodPresenter.java new file mode 100644 index 000000000..82bb1b361 --- /dev/null +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodPresenter.java @@ -0,0 +1,108 @@ +package com.hyperwallet.android.ui.transfermethod.view; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.hyperwallet.android.model.Error; +import com.hyperwallet.android.model.Errors; +import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; +import com.hyperwallet.android.model.transfermethod.TransferMethod; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepository; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodUpdateConfigurationRepository; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class UpdateTransferMethodPresenter implements UpdateTransferMethodContract.Presenter { + private static final String ERROR_UNMAPPED_FIELD = "ERROR_UNMAPPED_FIELD"; + private final TransferMethodUpdateConfigurationRepository mTransferMethodUpdateConfigurationRepository; + private final TransferMethodRepository mTransferMethodRepository; + private final UpdateTransferMethodContract.View mView; + + public UpdateTransferMethodPresenter(UpdateTransferMethodContract.View view, + TransferMethodUpdateConfigurationRepository transferMethodUpdateConfigurationRepository, + TransferMethodRepository transferMethodRepository) { + mView = view; + mTransferMethodUpdateConfigurationRepository = transferMethodUpdateConfigurationRepository; + mTransferMethodRepository = transferMethodRepository; + } + + @Override + public void loadTransferMethodConfigurationFields(boolean forceUpdate, @NonNull String transferMethodType) { + mView.showProgressBar(); + + if (forceUpdate) { + // mTransferMethodConfigurationRepository.refreshFields(); + } + + mTransferMethodUpdateConfigurationRepository.getFields(transferMethodType, + new TransferMethodUpdateConfigurationRepository.LoadFieldsCallback() { + @Override + public void onFieldsLoaded(@Nullable HyperwalletTransferMethodConfigurationField field) { + if (!mView.isActive()) { + return; + } + + mView.hideProgressBar(); + mView.showTransferMethodFields(field.getFields().getFieldGroups()); + // there can be multiple fees when we have flat fee + percentage fees + mView.showTransactionInformation(field.getFees(), field.getProcessingTime()); + } + + @Override + public void onError(@NonNull Errors errors) { + if (!mView.isActive()) { + return; + } + mView.hideProgressBar(); + mView.showErrorLoadTransferMethodConfigurationFields(errors.getErrors()); + } + }); + } + + @Override + public void updateTransferMethod(@NonNull TransferMethod transferMethod) { + mView.showCreateButtonProgressBar(); + mTransferMethodRepository.createTransferMethod(transferMethod, + new TransferMethodRepository.LoadTransferMethodCallback() { + @Override + public void onTransferMethodLoaded(TransferMethod transferMethod) { + + if (!mView.isActive()) { + return; + } + mView.hideCreateButtonProgressBar(); + mView.notifyTransferMethodUpdated(transferMethod); + } + + @Override + public void onError(Errors errors) { + if (!mView.isActive()) { + return; + } + + mView.hideCreateButtonProgressBar(); + if (errors.containsInputError()) { + mView.showInputErrors(errors.getErrors()); + } else { + mView.showErrorUpdateTransferMethod(errors.getErrors()); + } + } + }); + } + + @Override + public void handleUnmappedFieldError(@NonNull Map fieldSet, @NonNull List errors) { + for (Error error : errors) { + if (fieldSet.get(error.getFieldName()) == null) { + List errorList = new ArrayList() {{ + add(new Error(R.string.error_unmapped_field, ERROR_UNMAPPED_FIELD)); + }}; + mView.showErrorUpdateTransferMethod(errorList); + return; + } + } + } +} diff --git a/transfermethodui/src/main/res/layout/activity_update_transfer_method.xml b/transfermethodui/src/main/res/layout/activity_update_transfer_method.xml new file mode 100644 index 000000000..35a86b7d2 --- /dev/null +++ b/transfermethodui/src/main/res/layout/activity_update_transfer_method.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/transfermethodui/src/main/res/layout/fragment_update_transfer_method.xml b/transfermethodui/src/main/res/layout/fragment_update_transfer_method.xml new file mode 100644 index 000000000..45a3d274e --- /dev/null +++ b/transfermethodui/src/main/res/layout/fragment_update_transfer_method.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +