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/commonui/src/main/res/drawable/ic_edit.xml b/commonui/src/main/res/drawable/ic_edit.xml
new file mode 100644
index 000000000..bf16bd5cc
--- /dev/null
+++ b/commonui/src/main/res/drawable/ic_edit.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/commonui/src/main/res/drawable/ic_trash.xml b/commonui/src/main/res/drawable/ic_trash.xml
index 5fdcd6dfe..caa047ad8 100644
--- a/commonui/src/main/res/drawable/ic_trash.xml
+++ b/commonui/src/main/res/drawable/ic_trash.xml
@@ -1,20 +1,12 @@
-
-
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
diff --git a/commonui/src/main/res/values/strings.xml b/commonui/src/main/res/values/strings.xml
index d1ece3372..c350f1971 100644
--- a/commonui/src/main/res/values/strings.xml
+++ b/commonui/src/main/res/values/strings.xml
@@ -33,6 +33,7 @@
Authentication Error
Cancel
+ Edit
Remove
Are you sure?
diff --git a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImplTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImplTest.java
index bd55524c5..264e1d22c 100644
--- a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImplTest.java
+++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodUpdateConfigurationRepositoryImplTest.java
@@ -150,6 +150,21 @@ public Object answer(InvocationOnMock invocation) {
assertThat(errors.getErrors().get(0), is(inError));
}
+ @Test
+ public void testGetFields_callsListenerWithFieldResultFromCacheWhenNotNull() throws Exception {
+ String responseBody = externalResourceManager.getResourceContent(
+ "successful_tmc_update_field_bank_account_response.json");
+ final TransferMethodUpdateConfigurationFieldResult result = JsonUtils.fromJsonString(responseBody,
+ new TypeReference() {
+ });
+
+ FieldMapKey fieldMapKey = new FieldMapKey(TRANSFER_METHOD_TYPE);
+ when(mFieldsMap.get(fieldMapKey)).thenReturn(result);
+
+ mTransferMethodUpdateConfigurationRepositoryImplMock.getFields(TRANSFER_METHOD_TYPE,TRANSFER_TOKEN, loadFieldsCallback);
+ verify(loadFieldsCallback, never()).onError(any(Errors.class));
+ }
+
@Test
public void testRefreshFields_clearsFieldMapWhenNotEmpty() throws Exception {
String responseBody = externalResourceManager.getResourceContent(
diff --git a/transfermethodui/build.gradle b/transfermethodui/build.gradle
index cd908659d..207b83eb2 100644
--- a/transfermethodui/build.gradle
+++ b/transfermethodui/build.gradle
@@ -25,6 +25,7 @@ dependencies {
implementation project(':commonui')
implementation project(":userrepository")
implementation project(":transfermethodrepository")
+ implementation project(":transferui")
androidTestImplementation "androidx.test:rules:$testRulesVersion"
diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/EditTransferMethodTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/EditTransferMethodTest.java
new file mode 100644
index 000000000..e1144cdbf
--- /dev/null
+++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/EditTransferMethodTest.java
@@ -0,0 +1,257 @@
+package com.hyperwallet.android.ui.transfermethod;
+
+import android.app.Instrumentation;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.view.MenuItem;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.espresso.IdlingRegistry;
+import androidx.test.espresso.Root;
+import androidx.test.espresso.assertion.ViewAssertions;
+import androidx.test.espresso.matcher.ViewMatchers;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import com.hyperwallet.android.model.StatusTransition;
+import com.hyperwallet.android.ui.R;
+import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource;
+import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment;
+import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager;
+import com.hyperwallet.android.ui.testutils.rule.HyperwalletMockWebServer;
+import com.hyperwallet.android.ui.testutils.util.RecyclerViewCountAssertion;
+import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory;
+import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletInsightMockRule;
+import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity;
+import com.hyperwallet.android.ui.transfermethod.view.ListTransferMethodActivity;
+
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.replaceText;
+import static androidx.test.espresso.action.ViewActions.typeText;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.RootMatchers.isDialog;
+import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static androidx.test.espresso.matcher.ViewMatchers.hasSibling;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withParent;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static com.hyperwallet.android.model.StatusTransition.StatusDefinition.DE_ACTIVATED;
+import static com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment.RESULT_ERROR;
+import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.atPosition;
+import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.nestedScrollTo;
+import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.withDrawable;
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+
+@RunWith(AndroidJUnit4.class)
+public class EditTransferMethodTest {
+
+ private static final String ACCOUNT_NUMBER = "8017110254";
+ private static final String ROUTING_NUMBER = "211179539";
+
+ @ClassRule
+ public static HyperwalletExternalResourceManager sResourceManager = new HyperwalletExternalResourceManager();
+ @Rule
+ public HyperwalletInsightMockRule mHyperwalletInsightMockRule = new HyperwalletInsightMockRule();
+ @Rule
+ public HyperwalletMockWebServer mMockWebServer = new HyperwalletMockWebServer(8080);
+ @Rule
+ public ActivityTestRule mActivityTestRule =
+ new ActivityTestRule<>(ListTransferMethodActivity.class, true, false);
+
+ @Before
+ public void setup() {
+ mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager
+ .getResourceContent("authentication_token_response.json")).mock();
+ IdlingRegistry.getInstance().register(EspressoIdlingResource.getIdlingResource());
+ }
+
+ @After
+ public void cleanup() {
+ TransferMethodRepositoryFactory.clearInstance();
+ IdlingRegistry.getInstance().unregister(EspressoIdlingResource.getIdlingResource());
+ }
+
+
+ @Test
+ public void testUpdateTransferMethodFragment_verifyUpdateBankAccountTransferMethod() throws InterruptedException {
+ mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager
+ .getResourceContent("transfer_method_list_single_bank_account_response.json")).mock();
+ mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager
+ .getResourceContent("transfer_method_update_bankacount_response.json")).mock();
+
+
+ final CountDownLatch gate = new CountDownLatch(1);
+ final BroadcastReceiver br = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ gate.countDown();
+
+ StatusTransition statusTransition = intent.getParcelableExtra(
+ "hyperwallet-local-broadcast-payload");
+ assertThat("Transition is not valid", statusTransition.getTransition(), is(DE_ACTIVATED));
+ }
+ };
+
+ // run test
+ mActivityTestRule.launchActivity(null);
+ LocalBroadcastManager.getInstance(mActivityTestRule.getActivity().getApplicationContext())
+ .registerReceiver(br, new IntentFilter("ACTION_HYPERWALLET_TRANSFER_METHOD_DEACTIVATED"));
+
+ // assert
+ onView(withId(R.id.toolbar)).check(matches(isDisplayed()));
+ onView(withId(R.id.toolbar))
+ .check(matches(
+ hasDescendant(withText(R.string.mobileTransferMethodsHeader))));
+ onView(withId(R.id.fab)).check(matches(isDisplayed()));
+
+ onView(withId(R.id.list_transfer_method_item)).check(
+ matches(atPosition(0, hasDescendant(withText(R.string.bank_account_font_icon)))));
+ onView(withId(R.id.list_transfer_method_item)).check(
+ matches(atPosition(0, hasDescendant(withText(R.string.bank_account)))));
+ onView(withId(R.id.list_transfer_method_item)).check(
+ matches(atPosition(0, hasDescendant(withText("United States")))));
+ onView(withId(R.id.list_transfer_method_item)).check(
+ matches(atPosition(0, hasDescendant(withText(getEndingIn("1332"))))));
+ onView(withId(R.id.list_transfer_method_item)).check(
+ matches(atPosition(0, hasDescendant(withDrawable(R.drawable.ic_three_dots_16dp)))));
+
+ onView(allOf(instanceOf(ImageButton.class), hasSibling(withText(R.string.bank_account)))).perform(click())
+ .inRoot(Matchers.instanceOf(MenuItem.class));
+ onView(withDrawable(R.drawable.ic_trash)).check(matches(isDisplayed()));
+ onView(withText(R.string.edit)).check(matches(isDisplayed())).perform(click());
+
+ onView(withId(R.id.branchIdLabel)).check(matches(isDisplayed()));
+
+ onView(withId(R.id.branchId)).perform(nestedScrollTo()).check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
+ .check(matches(withText("021000021")));
+
+ onView(ViewMatchers.withId(R.id.branchIdLabel))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.bankAccountId))
+ .perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
+ .check(matches(withText("****")));
+
+ onView(ViewMatchers.withId(R.id.bankAccountIdLabel))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ // ACCOUNT HOLDER INFO
+ onView(
+ Matchers.allOf(
+ ViewMatchers.withId(R.id.section_header_title),
+ ViewMatchers.withText(R.string.account_holder)
+ )
+ )
+ .perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.firstName))
+ .perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
+ .check(matches(withText("Android Mobile")));
+
+ onView(ViewMatchers.withId(R.id.firstNameLabel))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.middleName))
+ .perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
+ .check(matches(withText("mobile-qa")));
+
+ onView(ViewMatchers.withId(R.id.middleNameLabel))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.lastName))
+ .perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
+ .check(matches(withText("UITest")));
+
+ onView(ViewMatchers.withId(R.id.lastNameLabel))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ // ADDRESS
+ onView(
+ Matchers.allOf(
+ ViewMatchers.withId(R.id.section_header_title),
+ ViewMatchers.withText(R.string.address)
+ )
+ ).perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.country))
+ .perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
+ .check(matches(withText("Canada")));
+
+ onView(ViewMatchers.withId(R.id.countryLabel))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.stateProvince))
+ .perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
+ .check(matches(withText("BC")));
+
+ onView(ViewMatchers.withId(R.id.stateProvinceLabel))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.addressLine1))
+ .perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
+ .check(matches(withText("475 howe st")));
+
+ onView(ViewMatchers.withId(R.id.addressLine1Label))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.city))
+ .perform(nestedScrollTo())
+ .check(matches(withText("vancouver")))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.cityLabel))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ onView(ViewMatchers.withId(R.id.postalCode))
+ .perform(nestedScrollTo())
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
+ .check(matches(withText("V6Z1L2")));
+
+ onView(ViewMatchers.withId(R.id.postalCodeLabel))
+ .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
+
+ }
+
+ private String getEndingIn(String ending) {
+ return String.format(InstrumentationRegistry.getInstrumentation().getTargetContext()
+ .getString(R.string.endingIn), ending);
+ }
+
+}
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/ListTransferMethodActivity.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodActivity.java
index f81e7a84b..ab11d8e15 100644
--- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodActivity.java
+++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodActivity.java
@@ -17,6 +17,7 @@
package com.hyperwallet.android.ui.transfermethod.view;
import static com.hyperwallet.android.ui.common.intent.HyperwalletIntent.SELECT_TRANSFER_METHOD_REQUEST_CODE;
+import static com.hyperwallet.android.ui.common.intent.HyperwalletIntent.UPDATE_TRANSFER_METHOD_REQUEST_CODE;
import static com.hyperwallet.android.ui.transfermethod.view.ListTransferMethodFragment.ARGUMENT_IS_TRANSFER_METHODS_RELOAD_NEEDED;
import android.content.Intent;
@@ -49,7 +50,7 @@ public class ListTransferMethodActivity extends AppCompatActivity implements
ListTransferMethodFragment.OnAddNewTransferMethodSelected,
ListTransferMethodFragment.OnDeactivateTransferMethodNetworkErrorCallback,
ListTransferMethodFragment.OnLoadTransferMethodNetworkErrorCallback,
- ListTransferMethodFragment.OnTransferMethodContextMenuDeletionSelected,
+ ListTransferMethodFragment.OnTransferMethodContextMenuItemSelected,
OnTransferMethodDeactivateCallback, OnNetworkErrorCallback {
public static final String TAG = "transfer-method:list:list-transfer-methods";
@@ -134,6 +135,9 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (fragment != null && fragment.getArguments() != null) {
fragment.getArguments().putBoolean(ARGUMENT_IS_TRANSFER_METHODS_RELOAD_NEEDED, true);
}
+ } else if (requestCode == UPDATE_TRANSFER_METHOD_REQUEST_CODE && resultCode == RESULT_OK) {
+ ActivityUtils.initFragment(this, ListTransferMethodFragment.newInstance(),
+ R.id.list_transfer_method_fragment);
}
}
@@ -177,6 +181,15 @@ public void showConfirmationDialog(@NonNull TransferMethod transferMethod) {
}
}
+ @Override
+ public void invokeTransferMethodEdit(@NonNull TransferMethod transferMethod) {
+ String token = transferMethod.getField(TransferMethod.TransferMethodFields.TOKEN);
+ Intent intent = new Intent(this, UpdateTransferMethodActivity.class);
+ intent.putExtra(UpdateTransferMethodActivity.EXTRA_TRANSFER_METHOD_TOKEN, token);
+ intent.putExtra(UpdateTransferMethodActivity.EXTRA_LOCK_SCREEN_ORIENTATION_TO_PORTRAIT, true);
+ startActivityForResult(intent, UPDATE_TRANSFER_METHOD_REQUEST_CODE);
+ }
+
@Override
public void confirm() {
mRetryCode = RETRY_CONFIRM_DEACTIVATE_TRANSFER_METHOD;
diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodFragment.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodFragment.java
index 9f4ccb6a8..f5c185311 100644
--- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodFragment.java
+++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodFragment.java
@@ -69,7 +69,7 @@ public class ListTransferMethodFragment extends Fragment implements ListTransfer
private View mProgressBar;
private ArrayList mTransferMethodList;
private OnAddNewTransferMethodSelected mOnAddNewTransferMethodSelected;
- private OnTransferMethodContextMenuDeletionSelected mOnTransferMethodContextMenuDeletionSelected;
+ private OnTransferMethodContextMenuItemSelected mOnTransferMethodContextMenuItemSelected;
private OnDeactivateTransferMethodNetworkErrorCallback mOnDeactivateTransferMethodNetworkErrorCallback;
private OnLoadTransferMethodNetworkErrorCallback mOnLoadTransferMethodNetworkErrorCallback;
private boolean mIsTransferMethodsReloadNeeded;
@@ -105,10 +105,10 @@ public void onAttach(Context context) {
}
try {
- mOnTransferMethodContextMenuDeletionSelected = (OnTransferMethodContextMenuDeletionSelected) context;
+ mOnTransferMethodContextMenuItemSelected = (OnTransferMethodContextMenuItemSelected) context;
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString() + " must implement "
- + OnTransferMethodContextMenuDeletionSelected.class.getCanonicalName());
+ + OnTransferMethodContextMenuItemSelected.class.getCanonicalName());
}
try {
@@ -144,7 +144,7 @@ public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
mIsTransferMethodsReloadNeeded = true;
}
mListTransferMethodAdapter = new ListTransferMethodAdapter(mTransferMethodList,
- mOnTransferMethodContextMenuDeletionSelected);
+ mOnTransferMethodContextMenuItemSelected);
recyclerView.setAdapter(mListTransferMethodAdapter);
}
@@ -187,7 +187,11 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
public void onResume() {
super.onResume();
mIsTransferMethodsReloadNeeded = getArguments().getBoolean(ARGUMENT_IS_TRANSFER_METHODS_RELOAD_NEEDED, true);
- if (mIsTransferMethodsReloadNeeded) {
+ loadTransferMethodsList(mIsTransferMethodsReloadNeeded);
+ }
+
+ private void loadTransferMethodsList(boolean shouldReload) {
+ if (shouldReload) {
getArguments().putBoolean(ARGUMENT_IS_TRANSFER_METHODS_RELOAD_NEEDED, false);
mPresenter.loadTransferMethods();
} else {
@@ -272,9 +276,11 @@ public void loadTransferMethods() {
mPresenter.loadTransferMethods();
}
- interface OnTransferMethodContextMenuDeletionSelected {
+ interface OnTransferMethodContextMenuItemSelected {
void showConfirmationDialog(@NonNull final TransferMethod transferMethod);
+
+ void invokeTransferMethodEdit(@NonNull final TransferMethod transferMethod);
}
interface OnAddNewTransferMethodSelected {
@@ -294,12 +300,12 @@ interface OnLoadTransferMethodNetworkErrorCallback {
private static class ListTransferMethodAdapter extends RecyclerView.Adapter {
private List mTransferMethodList;
- private OnTransferMethodContextMenuDeletionSelected mOnTransferMethodContextMenuDeletionSelected;
+ private OnTransferMethodContextMenuItemSelected mOnTransferMethodContextMenuItemSelected;
ListTransferMethodAdapter(final List transferMethodList,
- final OnTransferMethodContextMenuDeletionSelected onTransferMethodContextMenuSelection) {
+ final OnTransferMethodContextMenuItemSelected onTransferMethodContextMenuSelection) {
mTransferMethodList = transferMethodList;
- mOnTransferMethodContextMenuDeletionSelected = onTransferMethodContextMenuSelection;
+ mOnTransferMethodContextMenuItemSelected = onTransferMethodContextMenuSelection;
}
@NonNull
@@ -388,7 +394,10 @@ public void onClick(View v) {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.remove_account_context_option) {
- mOnTransferMethodContextMenuDeletionSelected.showConfirmationDialog(transferMethod);
+ mOnTransferMethodContextMenuItemSelected.showConfirmationDialog(transferMethod);
+ return true;
+ } if (item.getItemId() == R.id.edit_account_context_option) {
+ mOnTransferMethodContextMenuItemSelected.invokeTransferMethodEdit(transferMethod);
return true;
}
return false;
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..7bb47db9c
--- /dev/null
+++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodActivity.java
@@ -0,0 +1,169 @@
+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);
+ 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);
+ getSupportActionBar().setTitle("");
+
+ 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..d2fedfc65
--- /dev/null
+++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodContract.java
@@ -0,0 +1,65 @@
+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 HyperwalletTransferMethodConfigurationField field);
+
+ void showTransactionInformation(@NonNull final List fees,
+ @Nullable final ProcessingTime processingTime);
+
+ void showUpdateButtonProgressBar();
+
+ void hideUpdateButtonProgressBar();
+
+ 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, @NonNull final String transferMethodToken);
+
+ 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..49ad03ac6
--- /dev/null
+++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodFragment.java
@@ -0,0 +1,689 @@
+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.graphql.field.TransferMethodConfiguration;
+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.common.view.TransferMethodUtils;
+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_UPDATE_PROGRESS_BAR = "ARGUMENT_SHOW_UPDATE_PROGRESS_BAR";
+ private static final String ARGUMENT_WIDGET_STATE_MAP = "ARGUMENT_WIDGET_STATE_MAP";
+ private static final boolean FORCE_UPDATE = false;
+ private View mUpdateButtonProgressBar;
+ private Button mUpdateTransferMethodButton;
+ private ViewGroup mDynamicContainer;
+ private NestedScrollView mNestedScrollView;
+ private OnUpdateTransferMethodNetworkErrorCallback mOnUpdateTransferMethodNetworkErrorCallback;
+ private OnLoadTransferMethodConfigurationFieldsNetworkErrorCallback
+ mOnLoadTransferMethodConfigurationFieldsNetworkErrorCallback;
+ private UpdateTransferMethodContract.Presenter mPresenter;
+ private View mProgressBar;
+ private boolean mUpdateProgressBar;
+ private String mTransferMethodType;
+ private TransferMethod mTransferMethod;
+ private String mTransferMethodToken;
+ private HashMap mWidgetInputStateHashMap;
+ private boolean isEdited;
+
+ /**
+ * 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.putString(ARGUMENT_TRANSFER_METHOD_TOKEN, transferMethodToken);
+ 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);
+
+ mUpdateButtonProgressBar = view.findViewById(R.id.update_transfer_method_button_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()
+ .type(mTransferMethodType)
+ .build());
+
+ triggerUpdate();
+ }
+ });
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ TransferMethodRepositoryFactory factory = TransferMethodRepositoryFactory.getInstance();
+ mPresenter = new UpdateTransferMethodPresenter(this,
+ factory.getTransferMethodUpdateConfigurationRepository(),
+ 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);
+ mUpdateProgressBar = savedInstanceState.getBoolean(ARGUMENT_SHOW_UPDATE_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, mTransferMethodToken);
+ }
+
+ @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_UPDATE_PROGRESS_BAR, mUpdateProgressBar);
+ super.onSaveInstanceState(outState);
+ }
+
+ private void triggerUpdate() {
+ hideSoftKeys();
+ if (performValidation()) {
+ switch (mTransferMethodType) {
+ case BANK_ACCOUNT:
+ mTransferMethod = new BankAccount.Builder()
+ .token(mTransferMethodToken)
+ .build();
+ break;
+ case BANK_CARD:
+ mTransferMethod = new BankCard.Builder()
+ .token(mTransferMethodToken)
+ .build();
+ break;
+ case PAYPAL_ACCOUNT:
+ mTransferMethod = new PayPalAccount.Builder()
+ .token(mTransferMethodToken)
+ .build();
+ break;
+ case WIRE_ACCOUNT:
+ mTransferMethod = new BankAccount.Builder()
+ .token(mTransferMethodToken)
+ .transferMethodType(WIRE_ACCOUNT)
+ .build();
+ break;
+ case VENMO_ACCOUNT:
+ mTransferMethod = new VenmoAccount.Builder()
+ .token(mTransferMethodToken)
+ .build();
+ break;
+ case PAPER_CHECK:
+ mTransferMethod = new PaperCheck.Builder()
+ .token(mTransferMethodToken)
+ .build();
+ break;
+ default:
+ mTransferMethod = new TransferMethod();
+ 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();
+ if (widget.isEdited) {
+ isEdited = true;
+ mTransferMethod.setField(widget.getName(), widget.getValue());
+ }
+ }
+ }
+
+ if (isEdited) {
+ mPresenter.updateTransferMethod(mTransferMethod);
+ } else {
+ getActivity().finish();
+ }
+ }
+ }
+
+ 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()
+ .type(mTransferMethodType)
+ .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)
+ .type(mTransferMethodType)
+ .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);
+ }
+
+ private String getSectionHeaderText(@NonNull final FieldGroup group, @NonNull final Locale locale,
+ @NonNull final String currency) {
+ if (FieldGroup.GroupTypes.ACCOUNT_INFORMATION.equals(group.getGroupName())) {
+ return requireContext().getString(R.string.account_information,
+ locale.getDisplayName().toUpperCase(), currency);
+ }
+
+ 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 hyperwalletTransferMethodConfigurationField) {
+ mDynamicContainer.removeAllViews();
+ mUpdateTransferMethodButton.setVisibility(View.VISIBLE);
+
+ try {
+ TransferMethodConfiguration fields = hyperwalletTransferMethodConfigurationField.getFields();
+ Locale locale = new Locale.Builder().setRegion(fields.getCountry()).build();
+ mTransferMethodType = fields.getTransferMethodType();
+ String transferMethod = TransferMethodUtils.getTransferMethodName(getContext(), mTransferMethodType);
+ ((UpdateTransferMethodActivity) getActivity()).getSupportActionBar().setTitle(transferMethod);
+ // group
+ for (FieldGroup group : fields.getFieldGroups()) {
+ 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, fields.getCurrency()));
+ 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()
+ .type(mTransferMethodType)
+ .build());
+
+ if (mUpdateProgressBar) {
+ setVisibleAndDisableFields();
+ }
+ } catch (HyperwalletException e) {
+ throw new IllegalStateException("Widget initialization error: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public void showUpdateButtonProgressBar() {
+ mUpdateProgressBar = 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);
+ mUpdateButtonProgressBar.setVisibility(View.VISIBLE);
+ mUpdateTransferMethodButton.setBackgroundColor(getResources().getColor(R.color.colorSecondaryDark));
+ }
+
+ @Override
+ public void hideUpdateButtonProgressBar() {
+ mUpdateProgressBar = false;
+ getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+ mUpdateButtonProgressBar.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, mTransferMethodToken);
+ }
+
+ @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..7b920f6b6
--- /dev/null
+++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/UpdateTransferMethodPresenter.java
@@ -0,0 +1,110 @@
+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,
+ @NonNull final String transferMethodToken) {
+ mView.showProgressBar();
+
+ if (forceUpdate) {
+ mTransferMethodUpdateConfigurationRepository.refreshFields();
+ }
+
+ mTransferMethodUpdateConfigurationRepository.getFields(transferMethodType,
+ transferMethodToken,
+ new TransferMethodUpdateConfigurationRepository.LoadFieldsCallback() {
+ @Override
+ public void onFieldsLoaded(@Nullable HyperwalletTransferMethodConfigurationField field) {
+ if (!mView.isActive()) {
+ return;
+ }
+
+ mView.hideProgressBar();
+ mView.showTransferMethodFields(field);
+ // 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.showUpdateButtonProgressBar();
+ mTransferMethodRepository.updateTransferMethod(transferMethod,
+ new TransferMethodRepository.LoadTransferMethodCallback() {
+ @Override
+ public void onTransferMethodLoaded(TransferMethod transferMethod) {
+
+ if (!mView.isActive()) {
+ return;
+ }
+ mView.hideUpdateButtonProgressBar();
+ mView.notifyTransferMethodUpdated(transferMethod);
+ }
+
+ @Override
+ public void onError(Errors errors) {
+ if (!mView.isActive()) {
+ return;
+ }
+
+ mView.hideUpdateButtonProgressBar();
+ 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/java/com/hyperwallet/android/ui/transfermethod/view/widget/AbstractMaskedInputWidget.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/AbstractMaskedInputWidget.java
index 72cf67afa..87218b628 100644
--- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/AbstractMaskedInputWidget.java
+++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/AbstractMaskedInputWidget.java
@@ -69,7 +69,7 @@ String formatToApi(@NonNull final String displayValue) {
* @return a String formatted to the specification in the mask pattern
*/
String formatToDisplay(@NonNull final String apiValue) {
- if (mField != null && mField.getMask() != null) {
+ if (mField != null && mField.getMask() != null && !mField.isFieldValueMasked()) {
// format
String pattern = mField.getMask().getPattern(apiValue);
if (!TextUtils.isEmpty(pattern)) {
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 d0fb1c01e..0e9cb8311 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,7 +36,7 @@ public abstract class AbstractWidget {
protected final WidgetEventListener mListener;
protected int mBottomViewId = 0;
protected WidgetInputState mWidgetInputState;
- public Boolean isEdited = false;
+ public boolean isEdited = false;
public AbstractWidget(@Nullable Field field, @NonNull WidgetEventListener listener,
@Nullable String defaultValue, @NonNull View defaultFocusView) {
@@ -65,6 +65,9 @@ public boolean isValid() {
if (mField == null) {
return true;
}
+ else if(!isEdited && mField.isFieldValueMasked()) {
+ return true;
+ }
return !isInvalidEmptyValue() && !isInvalidLength() && !isInvalidRegex();
}
@@ -164,8 +167,8 @@ public DefaultKeyListener(View focusView, View clearFocusView) {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
+ isEdited = true;
if (event.getAction() == KeyEvent.ACTION_DOWN) {
- isEdited = true;
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/ExpireDateUtils.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/ExpireDateUtils.java
index d26dbd81b..697c890de 100644
--- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/ExpireDateUtils.java
+++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/widget/ExpireDateUtils.java
@@ -154,8 +154,11 @@ private Calendar getInputDate(@NonNull final String input) throws ParseException
//get month from server month part
private String getMonthFromServer(String[] splitDate) {
- return splitDate.length != 2 ? "" :
- splitDate[1].length() == 1 && Integer.parseInt(splitDate[1]) > 1 ?
- ZERO.concat(splitDate[1]) : splitDate[1];
+ if (splitDate.length >= 2) {
+ return splitDate[1].length() == 1 && Integer.parseInt(splitDate[1]) > 1 ? ZERO.concat(splitDate[1])
+ : splitDate[1];
+ } else {
+ return "";
+ }
}
}
\ No newline at end of file
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 5e872b011..690347109 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
@@ -57,6 +57,7 @@ public View getView(@NonNull final ViewGroup viewGroup) {
editText.setTextColor(viewGroup.getContext().getResources().getColor(R.color.regularColorSecondary));
editText.setEnabled(mField.isEditable());
+ editText.setSelectAllOnFocus(mField.isFieldValueMasked());
setIdFromFieldLabel(mTextInputLayout);
setIdFromFieldName(editText);
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
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 12f496f0f..7b99fbacb 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,6 +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());
+ editText.setSelectAllOnFocus(mField.isFieldValueMasked());
mTextInputLayout.setHint(mField.getLabel());
setIdFromFieldLabel(mTextInputLayout);
setIdFromFieldName(editText);
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..47ee191f6
--- /dev/null
+++ b/transfermethodui/src/main/res/layout/fragment_update_transfer_method.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/transfermethodui/src/main/res/menu/transfer_method_context_menu.xml b/transfermethodui/src/main/res/menu/transfer_method_context_menu.xml
index 93fd95f14..954b1b589 100644
--- a/transfermethodui/src/main/res/menu/transfer_method_context_menu.xml
+++ b/transfermethodui/src/main/res/menu/transfer_method_context_menu.xml
@@ -1,5 +1,9 @@