From 9ab848ea7413d66a47c1d7075e3a2a42da6acc1c Mon Sep 17 00:00:00 2001 From: Flavio Mattos Date: Tue, 30 Apr 2019 15:24:16 -0700 Subject: [PATCH 001/177] Version update and exempt maven local publish task from signing --- build.gradle | 2 +- ui/build.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 97bb15924..84879cd9e 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ allprojects { } - project.version = "1.0.0-beta01"; + project.version = "1.0.0-beta02-SNAPSHOT"; } task clean(type: Delete) { diff --git a/ui/build.gradle b/ui/build.gradle index ac183f7cc..f7328be25 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -46,7 +46,7 @@ dependencies { implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.recyclerview:recyclerview:1.0.0" - api 'com.hyperwallet.android:core-sdk:1.0.0-beta01' + api 'com.hyperwallet.android:core-sdk:1.0.0-beta02-SNAPSHOT' androidTestImplementation "androidx.test.ext:junit:1.1.0" androidTestImplementation "androidx.test:runner:1.1.1" @@ -149,7 +149,7 @@ publishing { tasks.withType(Sign) { onlyIf { - isReleaseVersion + isReleaseVersion && !gradle.taskGraph.hasTask("publishToMavenLocal") } } From adb8ecb7afab272932c70c7aed1085d65e4b938f Mon Sep 17 00:00:00 2001 From: Flavio Mattos Date: Fri, 10 May 2019 17:25:27 -0700 Subject: [PATCH 002/177] epic/HW-51230 add support paypal ui (#9) * HW-52538 add support to PayPal account --- .../ui/ListTransferMethodTest.java | 77 +++- .../android/transfermethod/ui/PayPalTest.java | 220 ++++++++++ .../TransferMethodRepositoryImpl.java | 54 ++- .../AddTransferMethodFragment.java | 8 + .../transfermethod/TransferMethodUtils.java | 4 + ui/src/main/res/values/ids.xml | 2 + ui/src/main/res/values/strings.xml | 4 +- .../TransferMethodRepositoryImplTest.java | 386 +++++++++++------- .../paypal_invalid_email_response.json | 8 + ui/src/test/resources/paypal_response.json | 17 + ...successful_tmc_paypal_fields_response.json | 46 +++ .../transfer_method_list_response.json | 17 + ...d_list_single_paypal_account_response.json | 32 ++ 13 files changed, 734 insertions(+), 141 deletions(-) create mode 100644 ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java create mode 100644 ui/src/test/resources/paypal_invalid_email_response.json create mode 100644 ui/src/test/resources/paypal_response.json create mode 100644 ui/src/test/resources/successful_tmc_paypal_fields_response.json create mode 100644 ui/src/test/resources/transfer_method_list_single_paypal_account_response.json diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/ListTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/ListTransferMethodTest.java index c9c491101..9c7038a6f 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/ListTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/ListTransferMethodTest.java @@ -90,7 +90,6 @@ public void testListTransferMethod_userHasMultipleTransferMethods() { mActivityTestRule.launchActivity(null); // assert - onView(withId(R.id.toolbar)).check(matches(isDisplayed())); onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) .check(matches(withText(R.string.title_activity_list_transfer_method))); onView(withId(R.id.fab)).check(matches(isDisplayed())); @@ -146,7 +145,17 @@ public void testListTransferMethod_userHasMultipleTransferMethods() { onView(withId(R.id.list_transfer_method_item)).check( matches(atPosition(4, hasDescendant(withDrawable(R.drawable.ic_three_dots_16dp))))); - onView(withId(R.id.list_transfer_method_item)).check(new RecyclerViewCountAssertion(5)); + onView(withId(R.id.list_transfer_method_item)).check( + matches(atPosition(5, hasDescendant(withText(R.string.paypal_account_font_icon))))); + onView(withId(R.id.list_transfer_method_item)).check( + matches(atPosition(5, hasDescendant(withText(R.string.paypal_account))))); + onView(withId(R.id.list_transfer_method_item)).check( + matches(atPosition(5, hasDescendant(withText("United States"))))); + //TODO: Try to check for non existence of transfer_method_type_description_2 + onView(withId(R.id.list_transfer_method_item)).check( + matches(atPosition(5, hasDescendant(withDrawable(R.drawable.ic_three_dots_16dp))))); + + onView(withId(R.id.list_transfer_method_item)).check(new RecyclerViewCountAssertion(6)); } @@ -337,6 +346,70 @@ public void onReceive(Context context, Intent intent) { } + @Test + public void testListTransferMethod_removePayPalAccount() throws InterruptedException { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("transfer_method_list_single_paypal_account_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("transfer_method_deactivate_success.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + + final CountDownLatch gate = new CountDownLatch(1); + final BroadcastReceiver br = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + gate.countDown(); + + HyperwalletStatusTransition 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(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_list_transfer_method))); + onView(withId(R.id.fab)).check(matches(isDisplayed())); + + onView(withId(R.id.list_transfer_method_item)).check( + matches(atPosition(0, hasDescendant(withText(R.string.paypal_account_font_icon))))); + onView(withId(R.id.list_transfer_method_item)).check( + matches(atPosition(0, hasDescendant(withText(R.string.paypal_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(withDrawable(R.drawable.ic_three_dots_16dp))))); + + onView(allOf(instanceOf(ImageButton.class), hasSibling(withText(R.string.paypal_account)))).perform(click()) + .inRoot(Matchers.instanceOf(MenuItem.class)); + onView(withDrawable(R.drawable.ic_trash)).check(matches(isDisplayed())); + onView(withText(R.string.menu_remove_account)).check(matches(isDisplayed())).perform(click()); + + // confirmation dialog is shown before deletion + onView(withText(R.string.transfer_method_remove_confirmation_title)).check(matches(isDisplayed())); + onView(withText(R.string.transfer_method_remove_confirmation)).check(matches(isDisplayed())); + onView(withId(android.R.id.button1)).check(matches(withText(R.string.remove_button_label))); + onView(withId(android.R.id.button2)).check(matches(withText(R.string.cancel_button_label))); + + onView(withId(android.R.id.button1)).perform(click()); + + gate.await(5, SECONDS); + LocalBroadcastManager.getInstance(mActivityTestRule.getActivity().getApplicationContext()).unregisterReceiver( + br); + assertThat("Action is not broadcasted", gate.getCount(), is(0L)); + + onView(withId(R.id.empty_transfer_method_list_layout)).check(matches(isDisplayed())); + onView(withText(R.string.empty_list_transfer_method_information)).check(matches(isDisplayed())); + + } + @Test public void testListTransferMethod_removeBankAccountClickCancel() throws InterruptedException { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java new file mode 100644 index 000000000..40574449f --- /dev/null +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java @@ -0,0 +1,220 @@ +package com.hyperwallet.android.transfermethod.ui; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; +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.isDisplayed; +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 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; + +import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; +import static java.net.HttpURLConnection.HTTP_CREATED; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.concurrent.TimeUnit.SECONDS; + +import static com.hyperwallet.android.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.util.EspressoUtils.withHint; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.widget.TextView; + +import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.espresso.IdlingRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.rule.ActivityTestRule; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.model.HyperwalletTransferMethod; +import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.repository.RepositoryFactory; +import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; +import com.hyperwallet.android.ui.util.EspressoIdlingResource; +import com.hyperwallet.android.util.TestAuthenticationProvider; + +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.util.concurrent.CountDownLatch; + +@RunWith(AndroidJUnit4.class) +public class PayPalTest { + + @ClassRule + public static HyperwalletExternalResourceManager sResourceManager = new HyperwalletExternalResourceManager(); + @Rule + public HyperwalletMockWebServer mMockWebServer = new HyperwalletMockWebServer(8080); + @Rule + public ActivityTestRule mActivityTestRule = + new ActivityTestRule(AddTransferMethodActivity.class, true, false) { + @Override + protected Intent getActivityIntent() { + Intent intent = new Intent(ApplicationProvider.getApplicationContext(), + AddTransferMethodActivity.class); + intent.putExtra("TRANSFER_METHOD_TYPE", "PAYPAL_ACCOUNT"); + intent.putExtra("TRANSFER_METHOD_COUNTRY", "US"); + intent.putExtra("TRANSFER_METHOD_CURRENCY", "USD"); + return intent; + } + }; + + @Before + public void setup() { + Hyperwallet.getInstance(new TestAuthenticationProvider()); + + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("authentication_token_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("successful_tmc_paypal_fields_response.json")).mock(); + } + + @After + public void cleanup() { + RepositoryFactory.clearInstance(); + } + + @Before + public void registerIdlingResource() { + IdlingRegistry.getInstance().register(EspressoIdlingResource.getIdlingResource()); + } + + @After + public void unregisterIdlingResource() { + IdlingRegistry.getInstance().unregister(EspressoIdlingResource.getIdlingResource()); + } + + @Test + public void testAddTransferMethod_displaysElementsOnTmcResponse() { + mActivityTestRule.launchActivity(null); + + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))).check( + matches(withText(R.string.paypal_account))); + + onView(withId(R.id.email)).check(matches(isDisplayed())); + onView(withId(R.id.emailLabel)).check(matches(withHint("Email"))); + + onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo()).check( + matches(withText(R.string.button_create_transfer_method))); + } + + @Test + public void testAddTransferMethod_displaysFeeElementsOnTmcResponse() { + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.add_transfer_method_fee_label)).check( + matches(withText(R.string.add_transfer_method_fee_label))); + onView(withId(R.id.add_transfer_method_processing_label)).check( + matches(withText(R.string.add_transfer_method_processing_time_label))); + onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("USD 0.25"))); + onView(withId(R.id.add_transfer_method_processing_time_value)).check(matches(withText("IMMEDIATE"))); + } + + @Test + public void testAddTransferMethod_returnsTokenOnPaypalAccountCreation() throws InterruptedException { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_CREATED).withBody(sResourceManager + .getResourceContent("paypal_response.json")).mock(); + + mActivityTestRule.launchActivity(null); + + final CountDownLatch gate = new CountDownLatch(1); + final BroadcastReceiver br = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + gate.countDown(); + + HyperwalletTransferMethod transferMethod = intent.getParcelableExtra( + "hyperwallet-local-broadcast-payload"); + assertThat("Bank Account Id is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.EMAIL), is("sunshine.carreiro@hyperwallet.com")); + } + }; + + LocalBroadcastManager.getInstance(mActivityTestRule.getActivity().getApplicationContext()) + .registerReceiver(br, new IntentFilter("ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED")); + + onView(withId(R.id.email)) + .perform(typeText("sunshine.carreiro@hyperwallet.com")) + .perform(closeSoftKeyboard()); + + onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); + + assertThat("Result code is incorrect", + mActivityTestRule.getActivityResult().getResultCode(), is(Activity.RESULT_OK)); + + gate.await(5, SECONDS); + LocalBroadcastManager.getInstance(mActivityTestRule.getActivity().getApplicationContext()).unregisterReceiver( + br); + assertThat("Action is not broadcasted", gate.getCount(), is(0L)); + } + + @Test + public void testAddTransferMethod_returnsErrorOnInvalidPattern() { + mActivityTestRule.launchActivity(null); + // Number input should not allow non numeric values + onView(withId(R.id.email)).perform(typeText("abc1test")); + onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); + + onView(withId(R.id.emailLabel)) + .check(matches(hasErrorText("accountNumber is invalid"))); + } + + @Test + public void testAddTransferMethod_returnsErrorOnInvalidPresence() { + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); + + onView(withId(R.id.emailLabel)) + .check(matches(hasErrorText("You must provide a value for this field"))); + } + + @Test + public void testAddTransferMethod_displaysErrorOnInvalidEmailAddress() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_BAD_REQUEST).withBody(sResourceManager + .getResourceContent("paypal_invalid_email_response.json")).mock(); + + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.email)) + .perform(typeText("invalidEmail@gmail.com")).perform(closeSoftKeyboard()); + onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); + + // check dialog content + onView(withText(R.string.error_dialog_title)).inRoot(isDialog()).check(matches(isDisplayed())); + onView(withText(containsString( + "PayPal transfer method email address should be same as profile email address."))) + .inRoot(isDialog()).check(matches(isDisplayed())); + onView(withId(android.R.id.button1)).check(matches(withText(R.string.close_button_label))); + onView(withId(android.R.id.button1)).perform(click()); + + // should display the add tm form + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))).check( + matches(withText(R.string.paypal_account))); + + // connectivity dialog should be dismissed and does not exist in ui + onView(withText(R.string.error_dialog_title)).check(doesNotExist()); + } + +} diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java index 0d43a7da7..7bc72f0c9 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java @@ -20,6 +20,7 @@ import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TYPE; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; +import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT; import android.os.Handler; @@ -34,6 +35,7 @@ import com.hyperwallet.android.model.HyperwalletBankCard; import com.hyperwallet.android.model.HyperwalletStatusTransition; import com.hyperwallet.android.model.HyperwalletTransferMethod; +import com.hyperwallet.android.model.PayPalAccount; import com.hyperwallet.android.model.paging.HyperwalletPageList; public class TransferMethodRepositoryImpl implements TransferMethodRepository { @@ -46,7 +48,7 @@ Hyperwallet getHyperwallet() { } @Override - public void createTransferMethod(final HyperwalletTransferMethod transferMethod, + public void createTransferMethod(@NonNull final HyperwalletTransferMethod transferMethod, LoadTransferMethodCallback callback) { switch (transferMethod.getField(TYPE)) { case BANK_ACCOUNT: @@ -55,6 +57,9 @@ public void createTransferMethod(final HyperwalletTransferMethod transferMethod, case BANK_CARD: createBankCard(transferMethod, callback); break; + case PAYPAL_ACCOUNT: + createPayPalAccount(transferMethod, callback); + break; default: //no default action } } @@ -89,6 +94,10 @@ public void deactivateTransferMethod(@NonNull final HyperwalletTransferMethod tr break; case BANK_CARD: deactivateBankCardAccount(transferMethod, callback); + break; + case PAYPAL_ACCOUNT: + deactivatePayPalAccount(transferMethod, callback); + break; default: //no default action } } @@ -135,6 +144,27 @@ public Handler getHandler() { }); } + private void deactivatePayPalAccount(@NonNull final HyperwalletTransferMethod transferMethod, + @NonNull final DeactivateTransferMethodCallback callback) { + getHyperwallet().deactivatePayPalAccount(transferMethod.getField(TOKEN), null, + new HyperwalletListener() { + @Override + public void onSuccess(@Nullable HyperwalletStatusTransition result) { + callback.onTransferMethodDeactivated(result); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getHyperwalletErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + private void createBankAccount(final HyperwalletTransferMethod transferMethod, final LoadTransferMethodCallback callback) { HyperwalletBankAccount bankAccount = (HyperwalletBankAccount) transferMethod; @@ -178,4 +208,26 @@ public Handler getHandler() { } }); } + + private void createPayPalAccount(@NonNull final HyperwalletTransferMethod 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.getHyperwalletErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java index 131ec7e0e..28d977e7a 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java @@ -21,6 +21,7 @@ import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TYPE; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; +import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT; import android.app.Activity; import android.content.Context; @@ -48,6 +49,7 @@ import com.hyperwallet.android.model.HyperwalletBankCard; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletTransferMethod; +import com.hyperwallet.android.model.PayPalAccount; import com.hyperwallet.android.model.meta.Fee; import com.hyperwallet.android.model.meta.HyperwalletField; import com.hyperwallet.android.ui.HyperwalletLocalBroadcast; @@ -466,6 +468,12 @@ private void triggerSubmit() { mTransferMethod = new HyperwalletBankCard.Builder(). transferMethodCountry(mCountry).transferMethodCurrency(mCurrency).build(); break; + case PAYPAL_ACCOUNT: + mTransferMethod = new PayPalAccount.Builder() + .transferMethodCountry(mCountry) + .transferMethodCurrency(mCurrency) + .build(); + break; default: mTransferMethod = new HyperwalletTransferMethod(); mTransferMethod.setField(TRANSFER_METHOD_COUNTRY, mCountry); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java index 37444ba38..7eb96f386 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java @@ -20,6 +20,7 @@ import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.PAPER_CHECK; +import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.PREPAID_CARD; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.WIRE_ACCOUNT; @@ -114,6 +115,9 @@ public static String getTransferMethodName(@NonNull final Context context, case WIRE_ACCOUNT: title = context.getString(R.string.wire_account); break; + case PAYPAL_ACCOUNT: + title = context.getString(R.string.paypal_account); + break; default: title = transferMethodType.toLowerCase(Locale.ROOT) + context.getString( R.string.not_translated_in_braces); diff --git a/ui/src/main/res/values/ids.xml b/ui/src/main/res/values/ids.xml index 64c8eb320..df6202824 100644 --- a/ui/src/main/res/values/ids.xml +++ b/ui/src/main/res/values/ids.xml @@ -12,4 +12,6 @@ + + \ No newline at end of file diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml index 4774946af..7e43ad98f 100644 --- a/ui/src/main/res/values/strings.xml +++ b/ui/src/main/res/values/strings.xml @@ -72,12 +72,14 @@ Wire Account Paper Check Prepaid Card + PayPal \uE000 \uE005 \uE00D \uE002 - \uE00E + \uE00A + \uE021 Search Hint Search Country diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java index 3178ef652..77244db89 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java @@ -10,15 +10,15 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.ACTIVATED; import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.DE_ACTIVATED; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.BANK_ACCOUNT_ID; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.BANK_NAME; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.STATUS; +import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TOKEN; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_CURRENCY; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TYPE; @@ -33,6 +33,7 @@ import com.hyperwallet.android.model.HyperwalletStatusTransition; import com.hyperwallet.android.model.HyperwalletTransferMethod; import com.hyperwallet.android.model.HyperwalletTransferMethodPagination; +import com.hyperwallet.android.model.PayPalAccount; import com.hyperwallet.android.model.paging.HyperwalletPageList; import org.junit.Before; @@ -59,6 +60,12 @@ public class TransferMethodRepositoryImplTest { @Mock private Hyperwallet mHyperwallet; + @Mock + private TransferMethodRepository.DeactivateTransferMethodCallback mDeactivateTransferMethodCallback; + @Mock + private TransferMethodRepository.LoadTransferMethodListCallback mLoadTransferMethodListCallback; + @Mock + private TransferMethodRepository.LoadTransferMethodCallback mLoadTransferMethodCallback; @Captor private ArgumentCaptor mErrorsArgumentCaptor; @Captor @@ -66,6 +73,8 @@ public class TransferMethodRepositoryImplTest { @Captor private ArgumentCaptor mBankCardArgumentCaptor; @Captor + private ArgumentCaptor mPayPalAccountArgumentCaptor; + @Captor private ArgumentCaptor mStatusTransitionArgumentCaptor; @Captor private ArgumentCaptor> mListTransferMethodCaptor; @@ -82,7 +91,7 @@ public void setup() { } @Test - public void testCreateTransferMethod_callsListenerWithBankAccountOnSuccess() { + public void testCreateTransferMethod_bankAccountWithSuccess() { HyperwalletBankAccount bankAccount = new HyperwalletBankAccount .Builder("CA", "CAD", "3423423432") .build(); @@ -100,14 +109,12 @@ public Object answer(InvocationOnMock invocation) { } }).when(mHyperwallet).createBankAccount(any(HyperwalletBankAccount.class), ArgumentMatchers.>any()); - TransferMethodRepository.LoadTransferMethodCallback mockCallback = mock( - TransferMethodRepository.LoadTransferMethodCallback.class); // test - mTransferMethodRepository.createTransferMethod(bankAccount, mockCallback); + mTransferMethodRepository.createTransferMethod(bankAccount, mLoadTransferMethodCallback); - verify(mockCallback).onTransferMethodLoaded(mBankAccountArgumentCaptor.capture()); - verify(mockCallback, never()).onError(any(HyperwalletErrors.class)); + verify(mLoadTransferMethodCallback).onTransferMethodLoaded(mBankAccountArgumentCaptor.capture()); + verify(mLoadTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); HyperwalletBankAccount transferMethod = mBankAccountArgumentCaptor.getValue(); assertThat(transferMethod, is(notNullValue())); @@ -119,7 +126,7 @@ public Object answer(InvocationOnMock invocation) { } @Test - public void testCreateTransferMethod_callsListenerWithErrorOnFailure() { + public void testCreateTransferMethod_bankAccountWithError() { HyperwalletBankAccount bankAccount = new HyperwalletBankAccount .Builder("US", "USD", "23432432") .build(); @@ -139,113 +146,86 @@ public Object answer(InvocationOnMock invocation) { } }).when(mHyperwallet).createBankAccount(any(HyperwalletBankAccount.class), ArgumentMatchers.>any()); - TransferMethodRepository.LoadTransferMethodCallback mockCallback = mock( - TransferMethodRepository.LoadTransferMethodCallback.class); // test - mTransferMethodRepository.createTransferMethod(bankAccount, mockCallback); + mTransferMethodRepository.createTransferMethod(bankAccount, mLoadTransferMethodCallback); - verify(mockCallback).onError(mErrorsArgumentCaptor.capture()); - verify(mockCallback, never()).onTransferMethodLoaded(any(HyperwalletTransferMethod.class)); + verify(mLoadTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); + verify(mLoadTransferMethodCallback, never()).onTransferMethodLoaded(any(HyperwalletTransferMethod.class)); assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); } + @Test - public void testLoadTransferMethod_userContextHasBankAccount() { + public void testDeactivateTransferMethod_bankAccountWithSuccess() { HyperwalletBankAccount bankAccount = new HyperwalletBankAccount .Builder("CA", "CAD", "3423423432") + .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56") .build(); - - List accounts = new ArrayList<>(); - accounts.add(bankAccount); - final HyperwalletPageList pageList = new HyperwalletPageList<>(accounts); - - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; - listener.onSuccess(pageList); - return listener; - } - }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodPagination) any(), - ArgumentMatchers.>>any()); - TransferMethodRepository.LoadTransferMethodListCallback mockCallback = mock( - TransferMethodRepository.LoadTransferMethodListCallback.class); - - // test - mTransferMethodRepository.loadTransferMethod(mockCallback); - - verify(mockCallback).onTransferMethodListLoaded(mListTransferMethodCaptor.capture()); - verify(mockCallback, never()).onError(any(HyperwalletErrors.class)); - - List transferMethods = mListTransferMethodCaptor.getValue(); - assertThat(transferMethods, hasSize(1)); - assertThat(transferMethods.get(0).getField(TRANSFER_METHOD_COUNTRY), is("CA")); - assertThat(transferMethods.get(0).getField(TRANSFER_METHOD_CURRENCY), is("CAD")); - assertThat(transferMethods.get(0).getField(BANK_ACCOUNT_ID), is("3423423432")); - } - - @Test - public void testLoadTransferMethod_userContextEmptyAccounts() { - + bankAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) { - HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; - listener.onSuccess(null); + HyperwalletStatusTransition statusTransition = new HyperwalletStatusTransition(DE_ACTIVATED); + statusTransition.setNotes("Closing this account."); + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onSuccess(statusTransition); return listener; } - }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodPagination) any(), - ArgumentMatchers.>>any()); - TransferMethodRepository.LoadTransferMethodListCallback mockCallback = mock( - TransferMethodRepository.LoadTransferMethodListCallback.class); + }).when(mHyperwallet).deactivateBankAccount(anyString(), ArgumentMatchers.isNull(), + ArgumentMatchers.>any()); // test - mTransferMethodRepository.loadTransferMethod(mockCallback); + mTransferMethodRepository.deactivateTransferMethod(bankAccount, mDeactivateTransferMethodCallback); - verify(mockCallback).onTransferMethodListLoaded(mListTransferMethodCaptor.capture()); - verify(mockCallback, never()).onError(any(HyperwalletErrors.class)); + verify(mDeactivateTransferMethodCallback).onTransferMethodDeactivated( + mStatusTransitionArgumentCaptor.capture()); + verify(mDeactivateTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); - List transferMethods = mListTransferMethodCaptor.getValue(); - assertThat(transferMethods, is(nullValue())); + HyperwalletStatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); + assertThat(statusTransition, is(notNullValue())); + assertThat(statusTransition.getTransition(), is(DE_ACTIVATED)); + assertThat(statusTransition.getNotes(), is("Closing this account.")); } @Test - public void testLoadTransferMethod_hasErrors() { - + public void testDeactivateTransferMethod_bankAccountWithError() { + HyperwalletBankAccount bankAccount = new HyperwalletBankAccount + .Builder("CA", "CAD", "3423423432") + .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56") + .build(); + bankAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); - doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) { - HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; List errorList = new ArrayList<>(); errorList.add(error); HyperwalletErrors errors = new HyperwalletErrors(errorList); listener.onFailure(new HyperwalletException(errors)); return listener; } - }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodPagination) any(), - ArgumentMatchers.>>any()); - TransferMethodRepository.LoadTransferMethodListCallback mockCallback = mock( - TransferMethodRepository.LoadTransferMethodListCallback.class); + }).when(mHyperwallet).deactivateBankAccount(anyString(), ArgumentMatchers.isNull(), + ArgumentMatchers.>any()); // test - mTransferMethodRepository.loadTransferMethod(mockCallback); + mTransferMethodRepository.deactivateTransferMethod(bankAccount, mDeactivateTransferMethodCallback); - verify(mockCallback, never()).onTransferMethodListLoaded(ArgumentMatchers.anyList()); - verify(mockCallback).onError(mErrorsArgumentCaptor.capture()); + verify(mDeactivateTransferMethodCallback, never()).onTransferMethodDeactivated( + any(HyperwalletStatusTransition.class)); + verify(mDeactivateTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); } @Test - public void testDeactivateBankAccount_successfullyDeactivatedBankAccount() { - HyperwalletBankAccount bankAccount = new HyperwalletBankAccount - .Builder("CA", "CAD", "3423423432") - .token("some token") + public void testDeactivateTransferMethod_bankCardWithSuccess() { + HyperwalletBankCard bankCard = new HyperwalletBankCard + .Builder("CA", "CAD", "1232345456784", "2019-05", "234") + .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56") .build(); - bankAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + bankCard.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) { @@ -255,17 +235,15 @@ public Object answer(InvocationOnMock invocation) { listener.onSuccess(statusTransition); return listener; } - }).when(mHyperwallet).deactivateBankAccount(anyString(), ArgumentMatchers.isNull(), + }).when(mHyperwallet).deactivateBankCard(anyString(), ArgumentMatchers.isNull(), ArgumentMatchers.>any()); - TransferMethodRepository.DeactivateTransferMethodCallback mockCallback = mock( - TransferMethodRepository.DeactivateTransferMethodCallback.class); - // test - mTransferMethodRepository.deactivateTransferMethod(bankAccount, mockCallback); + mTransferMethodRepository.deactivateTransferMethod(bankCard, mDeactivateTransferMethodCallback); - verify(mockCallback).onTransferMethodDeactivated(mStatusTransitionArgumentCaptor.capture()); - verify(mockCallback, never()).onError(any(HyperwalletErrors.class)); + verify(mDeactivateTransferMethodCallback).onTransferMethodDeactivated( + mStatusTransitionArgumentCaptor.capture()); + verify(mDeactivateTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); HyperwalletStatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); assertThat(statusTransition, is(notNullValue())); @@ -274,15 +252,12 @@ public Object answer(InvocationOnMock invocation) { } @Test - public void testDeactivateBankAccount_hasErrorOnDeactivate() { - TransferMethodRepositoryImpl mTransferMethodRepository = spy(TransferMethodRepositoryImpl.class); - doReturn(mHyperwallet).when(mTransferMethodRepository).getHyperwallet(); - - HyperwalletBankAccount bankAccount = new HyperwalletBankAccount - .Builder("CA", "CAD", "3423423432") - .token("some token") + public void testDeactivateTransferMethod_bankCardWithError() { + HyperwalletBankCard bankCard = new HyperwalletBankCard + .Builder("CA", "CAD", "1232345456784", "2019-05", "234") + .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56") .build(); - bankAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + bankCard.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); doAnswer(new Answer() { @Override @@ -294,27 +269,23 @@ public Object answer(InvocationOnMock invocation) { listener.onFailure(new HyperwalletException(errors)); return listener; } - }).when(mHyperwallet).deactivateBankAccount(anyString(), ArgumentMatchers.isNull(), + }).when(mHyperwallet).deactivateBankCard(anyString(), ArgumentMatchers.isNull(), ArgumentMatchers.>any()); - TransferMethodRepository.DeactivateTransferMethodCallback mockCallback = mock( - TransferMethodRepository.DeactivateTransferMethodCallback.class); // test - mTransferMethodRepository.deactivateTransferMethod(bankAccount, mockCallback); + mTransferMethodRepository.deactivateTransferMethod(bankCard, mDeactivateTransferMethodCallback); - verify(mockCallback, never()).onTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); - verify(mockCallback).onError(mErrorsArgumentCaptor.capture()); + verify(mDeactivateTransferMethodCallback, never()).onTransferMethodDeactivated( + any(HyperwalletStatusTransition.class)); + verify(mDeactivateTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); } @Test - public void testDeactivateBankCard_successfullyDeactivatedBankCard() { - HyperwalletBankCard bankCard = new HyperwalletBankCard - .Builder("CA", "CAD", "1232345456784", "2019-05", "234") - .token("some token") - .build(); - bankCard.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + public void testDeactivateTransferMethod_payPalAccountWithSuccess() { + PayPalAccount payPalAccount = new PayPalAccount.Builder("US", "US", "jsmith4@hyperwallet.com") + .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56").build(); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) { @@ -324,17 +295,15 @@ public Object answer(InvocationOnMock invocation) { listener.onSuccess(statusTransition); return listener; } - }).when(mHyperwallet).deactivateBankCard(anyString(), ArgumentMatchers.isNull(), + }).when(mHyperwallet).deactivatePayPalAccount(anyString(), ArgumentMatchers.isNull(), ArgumentMatchers.>any()); - TransferMethodRepository.DeactivateTransferMethodCallback mockCallback = mock( - TransferMethodRepository.DeactivateTransferMethodCallback.class); - // test - mTransferMethodRepository.deactivateTransferMethod(bankCard, mockCallback); + mTransferMethodRepository.deactivateTransferMethod(payPalAccount, mDeactivateTransferMethodCallback); - verify(mockCallback).onTransferMethodDeactivated(mStatusTransitionArgumentCaptor.capture()); - verify(mockCallback, never()).onError(any(HyperwalletErrors.class)); + verify(mDeactivateTransferMethodCallback).onTransferMethodDeactivated( + mStatusTransitionArgumentCaptor.capture()); + verify(mDeactivateTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); HyperwalletStatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); assertThat(statusTransition, is(notNullValue())); @@ -343,15 +312,10 @@ public Object answer(InvocationOnMock invocation) { } @Test - public void testDeactivateBankCard_hasErrorOnDeactivate() { - TransferMethodRepositoryImpl mTransferMethodRepository = spy(TransferMethodRepositoryImpl.class); - doReturn(mHyperwallet).when(mTransferMethodRepository).getHyperwallet(); - - HyperwalletBankCard bankCard = new HyperwalletBankCard - .Builder("CA", "CAD", "1232345456784", "2019-05", "234") - .token("some token") - .build(); - bankCard.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + public void testDeactivateTransferMethod_payPalAccountWithError() { + PayPalAccount payPalAccount = new PayPalAccount.Builder("US", "US", "jsmith4@hyperwallet.com") + .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56").build(); + payPalAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); doAnswer(new Answer() { @Override @@ -363,23 +327,22 @@ public Object answer(InvocationOnMock invocation) { listener.onFailure(new HyperwalletException(errors)); return listener; } - }).when(mHyperwallet).deactivateBankCard(anyString(), ArgumentMatchers.isNull(), + }).when(mHyperwallet).deactivatePayPalAccount(anyString(), ArgumentMatchers.isNull(), ArgumentMatchers.>any()); - TransferMethodRepository.DeactivateTransferMethodCallback mockCallback = mock( - TransferMethodRepository.DeactivateTransferMethodCallback.class); // test - mTransferMethodRepository.deactivateTransferMethod(bankCard, mockCallback); + mTransferMethodRepository.deactivateTransferMethod(payPalAccount, mDeactivateTransferMethodCallback); - verify(mockCallback, never()).onTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); - verify(mockCallback).onError(mErrorsArgumentCaptor.capture()); + verify(mDeactivateTransferMethodCallback, never()).onTransferMethodDeactivated( + any(HyperwalletStatusTransition.class)); + verify(mDeactivateTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); } @Test - public void testCreateTransferMethod_callsListenerWithBankCardOnSuccess() { + public void testCreateTransferMethod_bankCardWithSuccess() { HyperwalletBankCard bankCard = new HyperwalletBankCard .Builder("CA", "CAD", "1232345456784", "2019-05", "234") .build(); @@ -398,14 +361,12 @@ public Object answer(InvocationOnMock invocation) { } }).when(mHyperwallet).createBankCard(any(HyperwalletBankCard.class), ArgumentMatchers.>any()); - TransferMethodRepository.LoadTransferMethodCallback mockCallback = mock( - TransferMethodRepository.LoadTransferMethodCallback.class); // test - mTransferMethodRepository.createTransferMethod(bankCard, mockCallback); + mTransferMethodRepository.createTransferMethod(bankCard, mLoadTransferMethodCallback); - verify(mockCallback).onTransferMethodLoaded(mBankCardArgumentCaptor.capture()); - verify(mockCallback, never()).onError(any(HyperwalletErrors.class)); + verify(mLoadTransferMethodCallback).onTransferMethodLoaded(mBankCardArgumentCaptor.capture()); + verify(mLoadTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); HyperwalletBankCard transferMethod = mBankCardArgumentCaptor.getValue(); assertThat(transferMethod, is(notNullValue())); @@ -415,12 +376,11 @@ public Object answer(InvocationOnMock invocation) { } @Test - public void testCreateTransferMethod_callsListenerWithErrorOnBankCardFailure() { + public void testCreateTransferMethod_bankCardWithError() { HyperwalletBankCard bankCard = new HyperwalletBankCard .Builder("CA", "CAD", "1232345456784", "2019-05", "234") .build(); - final HyperwalletError error = new HyperwalletError("bank card test message", "BANK_CARD_TEST_CODE"); doAnswer(new Answer() { @@ -436,14 +396,166 @@ public Object answer(InvocationOnMock invocation) { } }).when(mHyperwallet).createBankCard(any(HyperwalletBankCard.class), ArgumentMatchers.>any()); - TransferMethodRepository.LoadTransferMethodCallback mockCallback = mock( - TransferMethodRepository.LoadTransferMethodCallback.class); // test - mTransferMethodRepository.createTransferMethod(bankCard, mockCallback); + mTransferMethodRepository.createTransferMethod(bankCard, mLoadTransferMethodCallback); - verify(mockCallback).onError(mErrorsArgumentCaptor.capture()); - verify(mockCallback, never()).onTransferMethodLoaded(any(HyperwalletTransferMethod.class)); + verify(mLoadTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); + verify(mLoadTransferMethodCallback, never()).onTransferMethodLoaded(any(HyperwalletTransferMethod.class)); assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); } + + + @Test + public void testLoadTransferMethod_returnsBankAccount() { + HyperwalletBankAccount bankAccount = new HyperwalletBankAccount + .Builder("CA", "CAD", "3423423432") + .build(); + + List accounts = new ArrayList<>(); + accounts.add(bankAccount); + final HyperwalletPageList pageList = new HyperwalletPageList<>(accounts); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onSuccess(pageList); + return listener; + } + }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodPagination) any(), + ArgumentMatchers.>>any()); + + // test + mTransferMethodRepository.loadTransferMethod(mLoadTransferMethodListCallback); + + verify(mLoadTransferMethodListCallback).onTransferMethodListLoaded(mListTransferMethodCaptor.capture()); + verify(mLoadTransferMethodListCallback, never()).onError(any(HyperwalletErrors.class)); + + List transferMethods = mListTransferMethodCaptor.getValue(); + assertThat(transferMethods, hasSize(1)); + assertThat(transferMethods.get(0).getField(TRANSFER_METHOD_COUNTRY), is("CA")); + assertThat(transferMethods.get(0).getField(TRANSFER_METHOD_CURRENCY), is("CAD")); + assertThat(transferMethods.get(0).getField(BANK_ACCOUNT_ID), is("3423423432")); + } + + @Test + public void testLoadTransferMethod_returnsNoAccounts() { + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onSuccess(null); + return listener; + } + }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodPagination) any(), + ArgumentMatchers.>>any()); + + // test + mTransferMethodRepository.loadTransferMethod(mLoadTransferMethodListCallback); + + verify(mLoadTransferMethodListCallback).onTransferMethodListLoaded(mListTransferMethodCaptor.capture()); + verify(mLoadTransferMethodListCallback, never()).onError(any(HyperwalletErrors.class)); + + List transferMethods = mListTransferMethodCaptor.getValue(); + assertThat(transferMethods, is(nullValue())); + } + + @Test + public void testLoadTransferMethod_withError() { + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + List errorList = new ArrayList<>(); + errorList.add(error); + HyperwalletErrors errors = new HyperwalletErrors(errorList); + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodPagination) any(), + ArgumentMatchers.>>any()); + + // test + mTransferMethodRepository.loadTransferMethod(mLoadTransferMethodListCallback); + + verify(mLoadTransferMethodListCallback, never()).onTransferMethodListLoaded( + ArgumentMatchers.anyList()); + verify(mLoadTransferMethodListCallback).onError(mErrorsArgumentCaptor.capture()); + + assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); + } + + @Test + public void testCreateTransferMethod_payPalAccountWithSuccess() { + // prepare + final PayPalAccount returnedPayPalAccount = new PayPalAccount.Builder() + .transferMethodCurrency("USD") + .transferMethodCountry("US") + .email("money@mail.com") + .token("trm-token-1342242314") + .build(); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + returnedPayPalAccount.setField(STATUS, ACTIVATED); + listener.onSuccess(returnedPayPalAccount); + return listener; + } + }).when(mHyperwallet).createPayPalAccount(any(PayPalAccount.class), + ArgumentMatchers.>any()); + + PayPalAccount parameter = new PayPalAccount.Builder().build(); + + // test + mTransferMethodRepository.createTransferMethod(parameter, mLoadTransferMethodCallback); + + // verify + verify(mLoadTransferMethodCallback).onTransferMethodLoaded(mPayPalAccountArgumentCaptor.capture()); + verify(mLoadTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); + + // assert + PayPalAccount payPalAccount = mPayPalAccountArgumentCaptor.getValue(); + assertThat(payPalAccount, is(notNullValue())); + assertThat(payPalAccount.getCountry(), is("US")); + assertThat(payPalAccount.getCurrency(), is("USD")); + assertThat(payPalAccount.getEmail(), is("money@mail.com")); + assertThat(payPalAccount.getField(STATUS), is(ACTIVATED)); + assertThat(payPalAccount.getField(TOKEN), is("trm-token-1342242314")); + } + + @Test + public void testCreateTransferMethod_payPalAccountWithError() { + // prepare + final HyperwalletError returnedError = new HyperwalletError("PayPal test message", "PAYPAL_TEST_CODE"); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + + List errorList = new ArrayList<>(); + errorList.add(returnedError); + + listener.onFailure(new HyperwalletException(new HyperwalletErrors(errorList))); + return listener; + } + }).when(mHyperwallet).createPayPalAccount(any(PayPalAccount.class), + ArgumentMatchers.>any()); + PayPalAccount parameter = new PayPalAccount.Builder().build(); + + // test + mTransferMethodRepository.createTransferMethod(parameter, mLoadTransferMethodCallback); + + // verify + verify(mLoadTransferMethodCallback, never()).onTransferMethodLoaded(any(HyperwalletTransferMethod.class)); + verify(mLoadTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); + + // assert + assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(returnedError)); + } } \ No newline at end of file diff --git a/ui/src/test/resources/paypal_invalid_email_response.json b/ui/src/test/resources/paypal_invalid_email_response.json new file mode 100644 index 000000000..bb112d852 --- /dev/null +++ b/ui/src/test/resources/paypal_invalid_email_response.json @@ -0,0 +1,8 @@ +{ + "errors": [ + { + "message": "PayPal transfer method email address should be same as profile email address.", + "code": "CONSTRAINT_VIOLATIONS" + } + ] +} \ No newline at end of file diff --git a/ui/src/test/resources/paypal_response.json b/ui/src/test/resources/paypal_response.json new file mode 100644 index 000000000..e86bbde93 --- /dev/null +++ b/ui/src/test/resources/paypal_response.json @@ -0,0 +1,17 @@ +{ + "token": "trm-6a29ddd5-6913-479e-a60c-24dc6bf14cd4", + "type": "PAYPAL_ACCOUNT", + "status": "ACTIVATED", + "createdOn": "2019-05-08T00:25:23", + "transferMethodCountry": "US", + "transferMethodCurrency": "USD", + "email": "sunshine.carreiro@hyperwallet.com", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-d702cfa0-7cb1-491d-8f25-9b896003e872/paypal-accounts/trm-6a29ddd5-6913-479e-a60c-24dc6bf14cd4" + } + ] +} \ No newline at end of file diff --git a/ui/src/test/resources/successful_tmc_paypal_fields_response.json b/ui/src/test/resources/successful_tmc_paypal_fields_response.json new file mode 100644 index 000000000..06ec0fe45 --- /dev/null +++ b/ui/src/test/resources/successful_tmc_paypal_fields_response.json @@ -0,0 +1,46 @@ +{ + "data": { + "transferMethodConfigurations": { + "nodes": [ + { + "countries": [ + "US" + ], + "currencies": [ + "USD" + ], + "transferMethodType": "PAYPAL_ACCOUNT", + "profile": "INDIVIDUAL", + "processingTime": "IMMEDIATE", + "fees": { + "nodes": [ + { + "transferMethodType": "PAYPAL_ACCOUNT", + "country": "US", + "currency": "USD", + "feeRateType": "FLAT", + "value": "0.25" + } + ] + }, + "fields": [ + { + "category": "ACCOUNT", + "dataType": "TEXT", + "isRequired": true, + "label": "Email", + "name": "email", + "placeholder": "", + "regularExpression": "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$", + "validationMessage": { + "length": "", + "pattern": "accountNumber is invalid", + "empty": "You must provide a value for this field" + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/ui/src/test/resources/transfer_method_list_response.json b/ui/src/test/resources/transfer_method_list_response.json index a83276744..221efcdc8 100644 --- a/ui/src/test/resources/transfer_method_list_response.json +++ b/ui/src/test/resources/transfer_method_list_response.json @@ -146,6 +146,23 @@ "href": "https://localhost:8181/rest/v3/users/usr-a51c7522-ccba-4bcf-a6a7-bc59dae8f9b0/bank-accounts/trm-13141cde-56a1-4bde-ab82-534fde4d1cdb" } ] + }, + { + "token": "trm-f3f3d205-b7fb-4292-bd40-fbe814c7efd3", + "type": "PAYPAL_ACCOUNT", + "status": "ACTIVATED", + "createdOn": "2019-05-08T20:28:38", + "transferMethodCountry": "US", + "transferMethodCurrency": "USD", + "email": "honey.thigpen@ukbuilder.com", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d/transfer-methods/trm-f3f3d205-b7fb-4292-bd40-fbe814c7efd3" + } + ] } ], "links": [ diff --git a/ui/src/test/resources/transfer_method_list_single_paypal_account_response.json b/ui/src/test/resources/transfer_method_list_single_paypal_account_response.json new file mode 100644 index 000000000..14837f4d3 --- /dev/null +++ b/ui/src/test/resources/transfer_method_list_single_paypal_account_response.json @@ -0,0 +1,32 @@ +{ + "count": 1, + "offset": 0, + "limit": 10, + "data": [ + { + "token": "trm-f3f3d205-b7fb-4292-bd40-fbe814c7efd3", + "type": "PAYPAL_ACCOUNT", + "status": "ACTIVATED", + "createdOn": "2019-05-08T20:28:38", + "transferMethodCountry": "US", + "transferMethodCurrency": "USD", + "email": "honey.thigpen@ukbuilder.com", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d/transfer-methods/trm-f3f3d205-b7fb-4292-bd40-fbe814c7efd3" + } + ] + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d/transfer-methods?offset=0&limit=10&sortBy=-createdOn&status=ACTIVATED" + } + ] +} \ No newline at end of file From ab103e441d0db992f1f8f153c2f7452a53de9b75 Mon Sep 17 00:00:00 2001 From: Flavio Mattos Date: Mon, 13 May 2019 14:28:13 -0700 Subject: [PATCH 003/177] Preparing release beta02 --- CHANGELOG.md | 6 +++++- README.md | 2 +- build.gradle | 2 +- gradle.properties | 4 ++-- ui/build.gradle | 4 ++-- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7935478d..c167f1c0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,4 +5,8 @@ Changelog ------------------- - Initial release * UI components to create Bank Account and Bank Card for United States (USD) -* UI components to list and deactivate accounts \ No newline at end of file +* UI components to list and deactivate accounts + +1.0.0-beta02 +------------------- +* Added PayPal as a Transfer method \ No newline at end of file diff --git a/README.md b/README.md index 67156919f..3923e8130 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Note that this SDK is geared towards those who need both backend data and UI fea To install Hyperwallet UI SDK, you just need to add the dependency into your build.gradle file in Android Studio (or Gradle). For example: ```bash -api 'com.hyperwallet.android:ui-sdk:1.0.0-beta01' +api 'com.hyperwallet.android:ui-sdk:1.0.0-beta02' ``` ## Initialization diff --git a/build.gradle b/build.gradle index 84879cd9e..aa5a21068 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ allprojects { } - project.version = "1.0.0-beta02-SNAPSHOT"; + project.version = "1.0.0-beta02"; } task clean(type: Delete) { diff --git a/gradle.properties b/gradle.properties index 570bde865..7c3dc23f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ android.useAndroidX=true android.enableJetifier=true -sonatypeUsername=user -sonatypePassword=password \ No newline at end of file +sonatypeUsername= +sonatypePassword= \ No newline at end of file diff --git a/ui/build.gradle b/ui/build.gradle index f7328be25..5a2a56c8d 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -46,7 +46,7 @@ dependencies { implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.recyclerview:recyclerview:1.0.0" - api 'com.hyperwallet.android:core-sdk:1.0.0-beta02-SNAPSHOT' + api 'com.hyperwallet.android:core-sdk:1.0.0-beta02' androidTestImplementation "androidx.test.ext:junit:1.1.0" androidTestImplementation "androidx.test:runner:1.1.1" @@ -149,7 +149,7 @@ publishing { tasks.withType(Sign) { onlyIf { - isReleaseVersion && !gradle.taskGraph.hasTask("publishToMavenLocal") + isReleaseVersion && sonatypeUsername?.trim() && sonatypePassword?.trim() } } From 5b80c0cc9c6124dc589a84d16941a18d14770783 Mon Sep 17 00:00:00 2001 From: Flavio Mattos Date: Tue, 14 May 2019 17:27:58 -0700 Subject: [PATCH 004/177] Feature/hw 51711 get user details (#16) *HW-51711 Get user details --- ui/build.gradle | 5 +- ui/config/jacoco-settings.gradle | 4 +- .../transfermethod/ui/BankAccountTest.java | 1 + .../transfermethod/ui/BankCardTest.java | 1 + .../android/transfermethod/ui/PayPalTest.java | 1 + .../ui/SelectTransferMethodTest.java | 73 ++++ .../hyperwallet/android/ui/HyperwalletUi.java | 7 +- .../ui/repository/RepositoryFactory.java | 6 + ...TransferMethodConfigurationRepository.java | 3 +- ...sferMethodConfigurationRepositoryImpl.java | 8 +- .../android/ui/repository/UserRepository.java | 57 ++++ .../ui/repository/UserRepositoryImpl.java | 71 ++++ .../AddTransferMethodActivity.java | 9 +- .../AddTransferMethodContract.java | 3 +- .../AddTransferMethodFragment.java | 23 +- .../AddTransferMethodPresenter.java | 11 +- .../SelectTransferMethodContract.java | 5 +- .../SelectTransferMethodFragment.java | 13 +- .../SelectTransferMethodPresenter.java | 177 ++++++---- .../TransferMethodSelectionItem.java | 19 +- ...MethodConfigurationRepositoryImplTest.java | 9 +- .../ui/repository/UserRepositoryImplTest.java | 197 +++++++++++ .../AddTransferMethodPresenterTest.java | 28 +- .../SelectTransferMethodPresenterTest.java | 311 ++++++++++++++---- .../resources/user_business_response.json | 44 +++ ui/src/test/resources/user_response.json | 26 ++ 26 files changed, 928 insertions(+), 184 deletions(-) create mode 100644 ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepository.java create mode 100644 ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepositoryImpl.java create mode 100644 ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java create mode 100644 ui/src/test/resources/user_business_response.json create mode 100644 ui/src/test/resources/user_response.json diff --git a/ui/build.gradle b/ui/build.gradle index f7328be25..b31b0e293 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -22,10 +22,13 @@ android { } buildTypes { - dev { + release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + testCoverageEnabled true + } } lintOptions { diff --git a/ui/config/jacoco-settings.gradle b/ui/config/jacoco-settings.gradle index 1a29fbfa8..c810d1d89 100644 --- a/ui/config/jacoco-settings.gradle +++ b/ui/config/jacoco-settings.gradle @@ -35,7 +35,7 @@ def debugClassPaths = [ final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] -task jacocoTestReport(type: JacocoReport, dependsOn: 'testDevUnitTest') { +task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { group = 'Reporting' description = 'Generate Jacoco coverage reports.' @@ -68,7 +68,7 @@ task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: ) additionalSourceDirs = files(coverageSourceDirs) sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDevUnitTest.exec") + executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") violationRules { setFailOnViolation(true) diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java index 72594174c..3a48ac15e 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java @@ -84,6 +84,7 @@ protected Intent getActivityIntent() { intent.putExtra("TRANSFER_METHOD_TYPE", "BANK_ACCOUNT"); intent.putExtra("TRANSFER_METHOD_COUNTRY", "US"); intent.putExtra("TRANSFER_METHOD_CURRENCY", "USD"); + intent.putExtra("TRANSFER_METHOD_PROFILE_TYPE", "INDIVIDUAL"); return intent; } }; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java index b3cfa405e..8f05f330d 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java @@ -86,6 +86,7 @@ protected Intent getActivityIntent() { intent.putExtra("TRANSFER_METHOD_TYPE", "BANK_CARD"); intent.putExtra("TRANSFER_METHOD_COUNTRY", "US"); intent.putExtra("TRANSFER_METHOD_CURRENCY", "USD"); + intent.putExtra("TRANSFER_METHOD_PROFILE_TYPE", "INDIVIDUAL"); return intent; } }; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java index 40574449f..6bf0ec8bd 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java @@ -76,6 +76,7 @@ protected Intent getActivityIntent() { intent.putExtra("TRANSFER_METHOD_TYPE", "PAYPAL_ACCOUNT"); intent.putExtra("TRANSFER_METHOD_COUNTRY", "US"); intent.putExtra("TRANSFER_METHOD_CURRENCY", "USD"); + intent.putExtra("TRANSFER_METHOD_PROFILE_TYPE", "INDIVIDUAL"); return intent; } }; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java index 45ab1f01f..018556a36 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java @@ -5,6 +5,8 @@ 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.intent.Intents.intended; +import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra; import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; import static androidx.test.espresso.matcher.ViewMatchers.hasSibling; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; @@ -19,6 +21,14 @@ import static java.net.HttpURLConnection.HTTP_OK; +import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; +import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; +import static com.hyperwallet.android.model.HyperwalletUser.ProfileTypes.BUSINESS; +import static com.hyperwallet.android.model.HyperwalletUser.ProfileTypes.INDIVIDUAL; +import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_COUNTRY; +import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY; +import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE; +import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_TYPE; import static com.hyperwallet.android.util.EspressoUtils.atPosition; import static com.hyperwallet.android.util.EspressoUtils.withDrawable; @@ -26,6 +36,7 @@ import androidx.test.espresso.IdlingRegistry; import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.espresso.intent.rule.IntentsTestRule; import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ActivityTestRule; @@ -57,6 +68,9 @@ public class SelectTransferMethodTest { @Rule public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(SelectTransferMethodActivity.class, true, false); + @Rule + public IntentsTestRule mIntentsTestRule = + new IntentsTestRule<>(SelectTransferMethodActivity.class, true, false); @Before public void setup() { @@ -83,6 +97,8 @@ public void unregisterIdlingResource() { @Test public void testSelectTransferMethod_verifyCorrectLabelsDisplayed() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); @@ -108,6 +124,8 @@ public void testSelectTransferMethod_verifyCorrectLabelsDisplayed() { @Test public void testSelectTransferMethod_verifyCountrySelectionList() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); @@ -130,6 +148,8 @@ public void testSelectTransferMethod_verifyCountrySelectionList() { @Test public void testSelectTransferMethod_verifyCountrySelectionSearch() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_large_response.json")).mock(); @@ -149,6 +169,9 @@ public void testSelectTransferMethod_verifyCountrySelectionSearch() { @Test public void testSelectTransferMethod_verifyCurrencySelectionList() { + + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); @@ -172,6 +195,8 @@ public void testSelectTransferMethod_verifyCurrencySelectionList() { @Test public void testSelectTransferMethod_verifyTransferMethodsList() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); @@ -201,6 +226,8 @@ public void testSelectTransferMethod_verifyTransferMethodsList() { @Test public void testSelectTransferMethod_verifyTransferMethodsListEmptyFee() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_empty_fee_response.json")).mock(); @@ -223,6 +250,8 @@ public void testSelectTransferMethod_verifyTransferMethodsListEmptyFee() { @Test public void testSelectTransferMethod_verifyTransferMethodsListEmptyProcessing() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_empty_processing_response.json")).mock(); @@ -245,6 +274,8 @@ public void testSelectTransferMethod_verifyTransferMethodsListEmptyProcessing() @Test public void testSelectTransferMethod_verifyTransferMethodsListUpdatedOnSelectionChange() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); @@ -269,8 +300,48 @@ public void testSelectTransferMethod_verifyTransferMethodsListUpdatedOnSelection } + @Test + public void testSelectTransferMethod_verifyIntentIndividualUser() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("successful_tmc_keys_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("successful_tmc_fields_response.json")).mock(); + + mIntentsTestRule.launchActivity(null); + + onView(withId(R.id.select_transfer_method_types_list)) + .perform(RecyclerViewActions.actionOnItem(withChild(withText(R.string.bank_account)), click())); + intended(hasExtra(EXTRA_TRANSFER_METHOD_PROFILE_TYPE, INDIVIDUAL)); + intended(hasExtra(EXTRA_TRANSFER_METHOD_COUNTRY, "US")); + intended(hasExtra(EXTRA_TRANSFER_METHOD_CURRENCY, "USD")); + intended(hasExtra(EXTRA_TRANSFER_METHOD_TYPE, BANK_ACCOUNT)); + } + + @Test + public void testSelectTransferMethod_verifyIntentBusinessUser() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_business_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("successful_tmc_keys_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("successful_tmc_fields_response.json")).mock(); + + mIntentsTestRule.launchActivity(null); + + onView(withId(R.id.select_transfer_method_types_list)) + .perform(RecyclerViewActions.actionOnItem(withChild(withText(R.string.bank_card)), click())); + intended(hasExtra(EXTRA_TRANSFER_METHOD_PROFILE_TYPE, BUSINESS)); + intended(hasExtra(EXTRA_TRANSFER_METHOD_COUNTRY, "US")); + intended(hasExtra(EXTRA_TRANSFER_METHOD_CURRENCY, "USD")); + intended(hasExtra(EXTRA_TRANSFER_METHOD_TYPE, BANK_CARD)); + } + @Test public void testSelectTransferMethod_clickBankAccountOpensAddTransferMethodUi() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager @@ -286,6 +357,8 @@ public void testSelectTransferMethod_clickBankAccountOpensAddTransferMethodUi() @Test public void testSelectTransferMethod_clickBankCardOpensAddTransferMethodUi() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager diff --git a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java index 666a2ef6c..4c5759831 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java @@ -21,6 +21,7 @@ import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_COUNTRY; import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY; +import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE; import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_TYPE; import android.content.Context; @@ -84,14 +85,18 @@ public Intent getIntentSelectTransferMethodActivity(@NonNull final Context conte * @param currency The transfer method currency code. ISO 4217 format. * @param transferMethodType The type of transfer method. For a complete list of transfer methods, see {@link * com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes} + * @param profileType The type of the account holder profile. For a complete list of options, see + * {@link com.hyperwallet.android.model.HyperwalletUser.ProfileTypes} * @return an Intent with the data necessary to launch the {@link AddTransferMethodActivity} */ public Intent getIntentAddTransferMethodActivity(@NonNull final Context context, @NonNull final String country, - @NonNull final String currency, @NonNull final String transferMethodType) { + @NonNull final String currency, @NonNull final String transferMethodType, + @NonNull final String profileType) { Intent intent = new Intent(context, AddTransferMethodActivity.class); intent.putExtra(EXTRA_TRANSFER_METHOD_COUNTRY, country); intent.putExtra(EXTRA_TRANSFER_METHOD_CURRENCY, currency); intent.putExtra(EXTRA_TRANSFER_METHOD_TYPE, transferMethodType); + intent.putExtra(EXTRA_TRANSFER_METHOD_PROFILE_TYPE, profileType); return intent; } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/RepositoryFactory.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/RepositoryFactory.java index ee5b44ea3..ec2a3a935 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/RepositoryFactory.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/RepositoryFactory.java @@ -31,10 +31,12 @@ public class RepositoryFactory { private static RepositoryFactory sInstance; private TransferMethodConfigurationRepository mTransferMethodConfigurationRepository; private TransferMethodRepository mTransferMethodRepository; + private UserRepository mUserRepository; private RepositoryFactory() { mTransferMethodConfigurationRepository = new TransferMethodConfigurationRepositoryImpl(); mTransferMethodRepository = new TransferMethodRepositoryImpl(); + mUserRepository = new UserRepositoryImpl(); } public static synchronized RepositoryFactory getInstance() { @@ -52,6 +54,10 @@ public TransferMethodRepository getTransferMethodRepository() { return mTransferMethodRepository; } + public UserRepository getUserRepository() { + return mUserRepository; + } + public static void clearInstance() { sInstance = null; } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java index e89c8bab5..bea52cb18 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java @@ -39,7 +39,8 @@ public interface TransferMethodConfigurationRepository { void getKeys(@NonNull final LoadKeysCallback loadKeysCallback); void getFields(@NonNull final String country, @NonNull final String currency, - @NonNull final String transferMethodType, @NonNull final LoadFieldsCallback loadFieldsCallback); + @NonNull final String transferMethodType, @NonNull final String transferMethodProfileType, + @NonNull final LoadFieldsCallback loadFieldsCallback); void refreshKeys(); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java index 008c87176..89aa23f59 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java @@ -47,7 +47,6 @@ import java.util.Objects; public class TransferMethodConfigurationRepositoryImpl implements TransferMethodConfigurationRepository { - private static final String INDIVIDUAL = "INDIVIDUAL"; private HyperwalletTransferMethodConfigurationKeyResult mTransferMethodConfigurationKeyResult; private final Handler mHandler; private final Map mFieldMap; @@ -104,9 +103,11 @@ public Handler getHandler() { void getTransferMethodConfigurationFieldResult(@NonNull final String country, @NonNull final String currency, @NonNull final String transferMethodType, + @NonNull final String transferMethodProfileType, @NonNull final LoadFieldsCallback loadFieldsCallback) { HyperwalletTransferMethodConfigurationFieldQuery query = - new HyperwalletTransferMethodConfigurationFieldQuery(country, currency, transferMethodType, INDIVIDUAL); + new HyperwalletTransferMethodConfigurationFieldQuery(country, currency, transferMethodType, + transferMethodProfileType); EspressoIdlingResource.increment(); getHyperwallet().retrieveTransferMethodConfigurationFields( @@ -146,6 +147,7 @@ public synchronized void getKeys(@NonNull final LoadKeysCallback loadKeysCallbac @Override public synchronized void getFields(@NonNull final String country, @NonNull final String currency, @NonNull final String transferMethodType, + @NonNull final String transferMethodProfileType, @NonNull final LoadFieldsCallback loadFieldsCallback) { FieldMapKey fieldMapKey = new FieldMapKey(country, currency, transferMethodType); HyperwalletTransferMethodConfigurationFieldResult transferMethodConfigurationFieldResult = mFieldMap.get( @@ -153,7 +155,7 @@ public synchronized void getFields(@NonNull final String country, @NonNull final // 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 (transferMethodConfigurationFieldResult == null) { - getTransferMethodConfigurationFieldResult(country, currency, transferMethodType, loadFieldsCallback); + getTransferMethodConfigurationFieldResult(country, currency, transferMethodType, transferMethodProfileType, loadFieldsCallback); } else { loadFieldsCallback.onFieldsLoaded(transferMethodConfigurationFieldResult); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepository.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepository.java new file mode 100644 index 000000000..902a8d13b --- /dev/null +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepository.java @@ -0,0 +1,57 @@ +/* + * 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.repository; + +import androidx.annotation.NonNull; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.HyperwalletUser; + +/** + * User Repository Contract + */ +public interface UserRepository { + /** + * Load user information + * + * @param callback @see {@link UserRepository.LoadUserCallback} + */ + void loadUser(@NonNull final LoadUserCallback callback); + + /** + * Set user to null + */ + void refreshUser(); + + /** + * Callback interface that responses to action when invoked to + * Load User information + *

+ * When User is properly loaded + * {@link UserRepository.LoadUserCallback#onUserLoaded(HyperwalletUser)} + * is invoked otherwise {@link UserRepository.LoadUserCallback#onError(HyperwalletErrors)} + * is called to further log or show error information + */ + interface LoadUserCallback { + + void onUserLoaded(@NonNull final HyperwalletUser user); + + void onError(@NonNull final HyperwalletErrors errors); + } +} diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepositoryImpl.java new file mode 100644 index 000000000..561d4cf85 --- /dev/null +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepositoryImpl.java @@ -0,0 +1,71 @@ +/* + * 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.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.HyperwalletUser; + +public class UserRepositoryImpl implements UserRepository { + + private Handler mHandler = new Handler(); + private HyperwalletUser mUser; + + @VisibleForTesting + Hyperwallet getHyperwallet() { + return Hyperwallet.getDefault(); + } + + @Override + public void loadUser(@NonNull final LoadUserCallback callback) { + if (mUser == null) { + getHyperwallet().getUser(new HyperwalletListener() { + @Override + public void onSuccess(@Nullable HyperwalletUser result) { + mUser = result; + callback.onUserLoaded(mUser); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getHyperwalletErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } else { + callback.onUserLoaded(mUser); + } + } + + @Override + public void refreshUser() { + mUser = null; + } +} diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java index 5e6fcba75..381446c7a 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java @@ -45,6 +45,7 @@ public class AddTransferMethodActivity extends AppCompatActivity implements public static final String EXTRA_TRANSFER_METHOD_COUNTRY = "TRANSFER_METHOD_COUNTRY"; public static final String EXTRA_TRANSFER_METHOD_CURRENCY = "TRANSFER_METHOD_CURRENCY"; public static final String EXTRA_TRANSFER_METHOD_TYPE = "TRANSFER_METHOD_TYPE"; + public static final String EXTRA_TRANSFER_METHOD_PROFILE_TYPE = "TRANSFER_METHOD_PROFILE_TYPE"; public static final int REQUEST_CODE = 100; private static final String ARGUMENT_RETRY_ACTION = "ARGUMENT_RETRY_ACTION"; private static final short RETRY_SHOW_ERROR_ADD_TRANSFER_METHOD = 100; @@ -75,7 +76,9 @@ public void onClick(View v) { initFragment(AddTransferMethodFragment.newInstance( getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_COUNTRY), getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_CURRENCY), - getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_TYPE))); + getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_TYPE), + getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_PROFILE_TYPE) + )); } else { mRetryCode = savedInstanceState.getShort(ARGUMENT_RETRY_ACTION); } @@ -181,7 +184,9 @@ private AddTransferMethodFragment getAddTransferMethodFragment() { fragment = AddTransferMethodFragment.newInstance( getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_COUNTRY), getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_CURRENCY), - getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_TYPE)); + getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_TYPE), + getIntent().getStringExtra(EXTRA_TRANSFER_METHOD_PROFILE_TYPE) + ); } return fragment; } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java index 6b2d136ba..93f3aa9da 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java @@ -71,6 +71,7 @@ interface Presenter { void loadTransferMethodConfigurationFields(boolean forceUpdate, @NonNull String country, @NonNull String currency, - @NonNull String transferMethodType); + @NonNull String transferMethodType, + @NonNull String transferMethodProfileType); } } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java index 28d977e7a..2507c3eed 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java @@ -71,6 +71,7 @@ public class AddTransferMethodFragment extends Fragment implements WidgetEventLi private static final String ARGUMENT_TRANSFER_METHOD_COUNTRY = "ARGUMENT_TRANSFER_METHOD_COUNTRY"; private static final String ARGUMENT_TRANSFER_METHOD_CURRENCY = "ARGUMENT_TRANSFER_METHOD_CURRENCY"; private static final String ARGUMENT_TRANSFER_METHOD_TYPE = "ARGUMENT_TRANSFER_METHOD_TYPE"; + private static final String ARGUMENT_TRANSFER_METHOD_PROFILE_TYPE = "ARGUMENT_TRANSFER_METHOD_PROFILE_TYPE"; private static final String ARGUMENT_SHOW_CREATE_PROGRESS_BAR = "ARGUMENT_SHOW_CREATE_PROGRESS_BAR"; private static final String ARGUMENT_TRANSFER_METHOD = "ARGUMENT_TRANSFER_METHOD"; private static final String ARGUMENT_WIDGET_STATE_MAP = "ARGUMENT_WIDGET_STATE_MAP"; @@ -89,6 +90,7 @@ public class AddTransferMethodFragment extends Fragment implements WidgetEventLi private boolean mShowCreateProgressBar; private String mTransferMethodType; private HyperwalletTransferMethod mTransferMethod; + private String mTransferMethodProfileType; private HashMap mWidgetInputStateHashMap; private TextView sectionHeaderTextView; @@ -101,28 +103,33 @@ public AddTransferMethodFragment() { /** * Creates new instance of AddTransferMethodFragment 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 AddTransferMethodFragment#newInstance(String, String, String)} is mandatory + * The parameters in {@link AddTransferMethodFragment#newInstance(String, String, String, String)} is mandatory * and should be supplied with correct data or this fragment will not initialize properly. * - * @param transferMethodCountry the country selected when creating transfer method - * @param transferMethodCurrency the currency selected when creating transfer method - * @param transferMethodType the type of transfer method needed to create transfer method + * @param transferMethodCountry the country selected when creating transfer method + * @param transferMethodCurrency the currency selected when creating transfer method + * @param transferMethodType the type of transfer method needed to create transfer method + * @param transferMethodProfileType the type of transfer method profile needed to create transfer method */ public static AddTransferMethodFragment newInstance(@NonNull String transferMethodCountry, @NonNull String transferMethodCurrency, - @NonNull String transferMethodType) { + @NonNull String transferMethodType, + @NonNull String transferMethodProfileType) { AddTransferMethodFragment addTransferMethodFragment = new AddTransferMethodFragment(); Bundle arguments = new Bundle(); addTransferMethodFragment.mCountry = transferMethodCountry; addTransferMethodFragment.mTransferMethodType = transferMethodType; addTransferMethodFragment.mCurrency = transferMethodCurrency; + addTransferMethodFragment.mTransferMethodProfileType = transferMethodProfileType; addTransferMethodFragment.mWidgetInputStateHashMap = new HashMap<>(1); addTransferMethodFragment.mTransferMethod = null; arguments.putString(ARGUMENT_TRANSFER_METHOD_COUNTRY, addTransferMethodFragment.mCountry); arguments.putString(ARGUMENT_TRANSFER_METHOD_CURRENCY, addTransferMethodFragment.mCurrency); arguments.putString(ARGUMENT_TRANSFER_METHOD_TYPE, addTransferMethodFragment.mTransferMethodType); + arguments.putString(ARGUMENT_TRANSFER_METHOD_PROFILE_TYPE, + addTransferMethodFragment.mTransferMethodProfileType); arguments.putParcelable(ARGUMENT_TRANSFER_METHOD, addTransferMethodFragment.mTransferMethod); arguments.putSerializable(ARGUMENT_WIDGET_STATE_MAP, addTransferMethodFragment.mWidgetInputStateHashMap); addTransferMethodFragment.setArguments(arguments); @@ -222,7 +229,8 @@ public void onViewStateRestored(@Nullable Bundle savedInstanceState) { @Override public void onResume() { super.onResume(); - mPresenter.loadTransferMethodConfigurationFields(FORCE_UPDATE, mCountry, mCurrency, mTransferMethodType); + mPresenter.loadTransferMethodConfigurationFields(FORCE_UPDATE, mCountry, mCurrency, mTransferMethodType, + mTransferMethodProfileType); } @Override @@ -254,7 +262,8 @@ public void retryAddTransferMethod() { @Override public void reloadTransferMethodConfigurationFields() { - mPresenter.loadTransferMethodConfigurationFields(FORCE_UPDATE, mCountry, mCurrency, mTransferMethodType); + mPresenter.loadTransferMethodConfigurationFields(FORCE_UPDATE, mCountry, mCurrency, mTransferMethodType, + mTransferMethodProfileType); } @Override diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java index dc048c1d1..73b10717d 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java @@ -75,7 +75,8 @@ public void onError(HyperwalletErrors errors) { @Override public void loadTransferMethodConfigurationFields(final boolean forceUpdate, @NonNull final String country, - @NonNull final String currency, @NonNull final String transferMethodType) { + @NonNull final String currency, @NonNull final String transferMethodType, + @NonNull final String transferMethodProfileType) { mView.showProgressBar(); if (forceUpdate) { @@ -83,7 +84,8 @@ public void loadTransferMethodConfigurationFields(final boolean forceUpdate, @No } mTransferMethodConfigurationRepository.getFields( - country, currency, transferMethodType, new TransferMethodConfigurationRepository.LoadFieldsCallback() { + country, currency, transferMethodType, transferMethodProfileType, + new TransferMethodConfigurationRepository.LoadFieldsCallback() { @Override public void onFieldsLoaded( HyperwalletTransferMethodConfigurationFieldResult transferMethodConfigurationFieldResult) { @@ -95,10 +97,11 @@ public void onFieldsLoaded( mView.showTransferMethodFields(transferMethodConfigurationFieldResult.getFields()); // there can be multiple fees when we have flat fee + percentage fees List fees = transferMethodConfigurationFieldResult - .getFees(country, currency, transferMethodType, "INDIVIDUAL"); + .getFees(country, currency, transferMethodType, transferMethodProfileType); mView.showTransactionInformation(fees, transferMethodConfigurationFieldResult - .getProcessingTime(country, currency, transferMethodType, "INDIVIDUAL")); + .getProcessingTime(country, currency, transferMethodType, + transferMethodProfileType)); } @Override diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodContract.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodContract.java index dc7538e82..ec4a747fb 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodContract.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodContract.java @@ -38,7 +38,8 @@ public interface SelectTransferMethodContract { interface View { - void showAddTransferMethod(String country, String currency, String transferMethodType); + void showAddTransferMethod(@NonNull final String country, @NonNull final String currency, + @NonNull final String transferMethodType, @NonNull final String profileType); void showErrorLoadTransferMethodConfigurationKeys(@NonNull final List errors); @@ -95,7 +96,7 @@ void loadTransferMethodTypes(final boolean forceUpdate, @NonNull final String co @NonNull final String currencyCode); void openAddTransferMethod(@NonNull final String country, @NonNull final String currency, - @NonNull final String transferMethodType); + @NonNull final String transferMethodType, @NonNull final String profileType); void loadCountrySelection(@NonNull final String countryCode); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java index ec2f3c9ba..db873d8f7 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java @@ -174,8 +174,9 @@ public void onClick(View v) { new TransferMethodSelectionItemListener() { @Override public void onTransferMethodSelected(TransferMethodSelectionItem transferMethodType) { - mPresenter.openAddTransferMethod(mSelectedCountryCode, mSelectedCurrencyCode, - transferMethodType.getTransferMethodType()); + mPresenter.openAddTransferMethod(transferMethodType.getCountry(), + transferMethodType.getCurrency(), + transferMethodType.getTransferMethodType(), transferMethodType.getProfileType()); } }); @@ -190,7 +191,9 @@ public void onTransferMethodSelected(TransferMethodSelectionItem transferMethodT public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); RepositoryFactory factory = RepositoryFactory.getInstance(); - mPresenter = new SelectTransferMethodPresenter(this, factory.getTransferMethodConfigurationRepository()); + mPresenter = new SelectTransferMethodPresenter(this, + factory.getTransferMethodConfigurationRepository(), + factory.getUserRepository()); } @@ -286,11 +289,13 @@ public void showCurrencySelectionDialog(@NonNull final TreeMap c } @Override - public void showAddTransferMethod(String country, String currency, String transferMethodType) { + public void showAddTransferMethod(@NonNull final String country, @NonNull final String currency, + @NonNull final String transferMethodType, @NonNull final String profileType) { Intent intent = new Intent(getActivity(), AddTransferMethodActivity.class); intent.putExtra(AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_COUNTRY, country); intent.putExtra(AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY, currency); intent.putExtra(AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_TYPE, transferMethodType); + intent.putExtra(AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE, profileType); getActivity().startActivityForResult(intent, AddTransferMethodActivity.REQUEST_CODE); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java index 8abdb1ce1..4524e8ff0 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java @@ -22,9 +22,11 @@ import androidx.annotation.Nullable; import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.HyperwalletUser; import com.hyperwallet.android.model.meta.Fee; import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationKeyResult; import com.hyperwallet.android.ui.repository.TransferMethodConfigurationRepository; +import com.hyperwallet.android.ui.repository.UserRepository; import java.util.ArrayList; import java.util.Currency; @@ -33,16 +35,17 @@ import java.util.TreeMap; public class SelectTransferMethodPresenter implements SelectTransferMethodContract.Presenter { - private static final String TAG = SelectTransferMethodPresenter.class.getName(); - private static final String INDIVIDUAL = "INDIVIDUAL"; private final TransferMethodConfigurationRepository mTransferMethodConfigurationRepository; + private final UserRepository mUserRepository; private final SelectTransferMethodContract.View mView; SelectTransferMethodPresenter(SelectTransferMethodContract.View view, - TransferMethodConfigurationRepository transferMethodConfigurationRepository) { + @NonNull final TransferMethodConfigurationRepository transferMethodConfigurationRepository, + @NonNull final UserRepository userRepository) { this.mView = view; this.mTransferMethodConfigurationRepository = transferMethodConfigurationRepository; + this.mUserRepository = userRepository; } @Override @@ -55,35 +58,50 @@ public void loadTransferMethodConfigurationKeys(final boolean forceUpdate, @NonN mTransferMethodConfigurationRepository.refreshKeys(); } - mTransferMethodConfigurationRepository.getKeys(new TransferMethodConfigurationRepository.LoadKeysCallback() { + mUserRepository.loadUser(new UserRepository.LoadUserCallback() { @Override - public void onKeysLoaded( - @Nullable final HyperwalletTransferMethodConfigurationKeyResult transferMethodConfigurationKeyResult) { - if (!mView.isActive()) { - return; - } - - mView.hideProgressBar(); - List transferMethodTypes = - transferMethodConfigurationKeyResult.getTransferMethods(countryCode, currencyCode, INDIVIDUAL); - - mView.showTransferMethodCountry(countryCode); - mView.showTransferMethodCurrency(currencyCode); - mView.showTransferMethodTypes(getTransferMethodSelectionItems(countryCode, currencyCode, - transferMethodTypes, transferMethodConfigurationKeyResult)); + public void onUserLoaded(@NonNull final HyperwalletUser user) { + mTransferMethodConfigurationRepository.getKeys( + new TransferMethodConfigurationRepository.LoadKeysCallback() { + @Override + public void onKeysLoaded( + @Nullable final HyperwalletTransferMethodConfigurationKeyResult transferMethodConfigurationKeyResult) { + if (!mView.isActive()) { + return; + } + mView.hideProgressBar(); + List transferMethodTypes = + transferMethodConfigurationKeyResult.getTransferMethods(countryCode, + currencyCode, user.getProfileType()); + + mView.showTransferMethodCountry(countryCode); + mView.showTransferMethodCurrency(currencyCode); + mView.showTransferMethodTypes(getTransferMethodSelectionItems(countryCode, currencyCode, + user.getProfileType(), transferMethodTypes, transferMethodConfigurationKeyResult)); + } + + @Override + public void onError(@NonNull final HyperwalletErrors errors) { + showErrorLoadTransferMethods(errors); + } + }); } @Override - public void onError(@NonNull final HyperwalletErrors errors) { - if (!mView.isActive()) { - return; - } - mView.hideProgressBar(); - mView.showErrorLoadTransferMethodConfigurationKeys(errors.getErrors()); + public void onError(@NonNull HyperwalletErrors errors) { + showErrorLoadTransferMethods(errors); } }); } + private void showErrorLoadTransferMethods(@NonNull HyperwalletErrors errors) { + if (!mView.isActive()) { + return; + } + mView.hideProgressBar(); + mView.showErrorLoadTransferMethodConfigurationKeys(errors.getErrors()); + } + @Override public void loadCurrency(final boolean forceUpdate, @NonNull final String countryCode) { @@ -91,30 +109,47 @@ public void loadCurrency(final boolean forceUpdate, @NonNull final String countr mTransferMethodConfigurationRepository.refreshKeys(); } - mTransferMethodConfigurationRepository.getKeys(new TransferMethodConfigurationRepository.LoadKeysCallback() { + mUserRepository.loadUser(new UserRepository.LoadUserCallback() { @Override - public void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKeyResult result) { - if (!mView.isActive()) { - return; - } - List transferMethodCurrencies = result.getCurrencies(countryCode); - List transferMethodTypes = result.getTransferMethods( - countryCode, transferMethodCurrencies.get(0), INDIVIDUAL); - - mView.showTransferMethodCountry(countryCode); - mView.showTransferMethodCurrency(transferMethodCurrencies.get(0)); - mView.showTransferMethodTypes(getTransferMethodSelectionItems(countryCode, - transferMethodCurrencies.get(0), transferMethodTypes, result)); + public void onUserLoaded(@NonNull final HyperwalletUser user) { + mTransferMethodConfigurationRepository.getKeys( + new TransferMethodConfigurationRepository.LoadKeysCallback() { + @Override + public void onKeysLoaded( + @Nullable final HyperwalletTransferMethodConfigurationKeyResult result) { + if (!mView.isActive()) { + return; + } + List transferMethodCurrencies = result.getCurrencies(countryCode); + List transferMethodTypes = result.getTransferMethods( + countryCode, transferMethodCurrencies.get(0), user.getProfileType()); + + mView.showTransferMethodCountry(countryCode); + mView.showTransferMethodCurrency(transferMethodCurrencies.get(0)); + mView.showTransferMethodTypes(getTransferMethodSelectionItems(countryCode, + transferMethodCurrencies.get(0), user.getProfileType(), transferMethodTypes, result)); + } + + @Override + public void onError(@NonNull final HyperwalletErrors errors) { + showErrorLoadCurrency(errors); + } + }); } @Override - public void onError(@NonNull final HyperwalletErrors errors) { - if (!mView.isActive()) { - return; - } - mView.showErrorLoadCurrency(errors.getErrors()); + public void onError(@NonNull HyperwalletErrors errors) { + showErrorLoadCurrency(errors); } }); + + } + + private void showErrorLoadCurrency(@NonNull HyperwalletErrors errors) { + if (!mView.isActive()) { + return; + } + mView.showErrorLoadCurrency(errors.getErrors()); } @Override @@ -124,37 +159,53 @@ public void loadTransferMethodTypes(final boolean forceUpdate, mTransferMethodConfigurationRepository.refreshKeys(); } - mTransferMethodConfigurationRepository.getKeys(new TransferMethodConfigurationRepository.LoadKeysCallback() { + mUserRepository.loadUser(new UserRepository.LoadUserCallback() { @Override - public void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKeyResult - transferMethodConfigurationKeyResult) { - if (!mView.isActive()) { - return; - } - - List transferMethodTypes = transferMethodConfigurationKeyResult.getTransferMethods( - countryCode, currencyCode, INDIVIDUAL); - - mView.showTransferMethodCountry(countryCode); - mView.showTransferMethodCurrency(currencyCode); - mView.showTransferMethodTypes(getTransferMethodSelectionItems(countryCode, currencyCode, - transferMethodTypes, transferMethodConfigurationKeyResult)); + public void onUserLoaded(@NonNull final HyperwalletUser user) { + mTransferMethodConfigurationRepository.getKeys( + new TransferMethodConfigurationRepository.LoadKeysCallback() { + @Override + public void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKeyResult + transferMethodConfigurationKeyResult) { + if (!mView.isActive()) { + return; + } + + List transferMethodTypes = + transferMethodConfigurationKeyResult.getTransferMethods( + countryCode, currencyCode, user.getProfileType()); + + mView.showTransferMethodCountry(countryCode); + mView.showTransferMethodCurrency(currencyCode); + mView.showTransferMethodTypes(getTransferMethodSelectionItems(countryCode, currencyCode, + user.getProfileType(), transferMethodTypes, transferMethodConfigurationKeyResult)); + } + + @Override + public void onError(@NonNull final HyperwalletErrors errors) { + if (!mView.isActive()) { + return; + } + mView.showErrorLoadTransferMethodTypes(errors.getErrors()); + } + }); } @Override - public void onError(@NonNull final HyperwalletErrors errors) { + public void onError(@NonNull HyperwalletErrors errors) { if (!mView.isActive()) { return; } mView.showErrorLoadTransferMethodTypes(errors.getErrors()); } }); + } @Override public void openAddTransferMethod(@NonNull final String country, @NonNull final String currency, - @NonNull final String transferMethodType) { - mView.showAddTransferMethod(country, currency, transferMethodType); + @NonNull final String transferMethodType, @NonNull final String profileType) { + mView.showAddTransferMethod(country, currency, transferMethodType, profileType); } @Override @@ -219,17 +270,19 @@ public void onError(@NonNull final HyperwalletErrors errors) { private List getTransferMethodSelectionItems( @NonNull final String country, @NonNull final String currency, + @NonNull final String userProfileType, @NonNull final List transferMethodTypes, @NonNull final HyperwalletTransferMethodConfigurationKeyResult result) { List selectionItems = new ArrayList<>(); for (String transferMethodType : transferMethodTypes) { - List fees = result.getFees(country, currency, transferMethodType, INDIVIDUAL); - String processingTime = result.getProcessingTime(country, currency, transferMethodType, INDIVIDUAL); - TransferMethodSelectionItem data = new TransferMethodSelectionItem(country, currency, INDIVIDUAL, + List fees = result.getFees(country, currency, transferMethodType, userProfileType); + String processingTime = result.getProcessingTime(country, currency, transferMethodType, userProfileType); + TransferMethodSelectionItem data = new TransferMethodSelectionItem(country, currency, userProfileType, transferMethodType, processingTime, fees); selectionItems.add(data); } return selectionItems; } + } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java index ca5e04c9e..d065d7ac1 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java @@ -16,6 +16,8 @@ */ package com.hyperwallet.android.ui.transfermethod; +import androidx.annotation.NonNull; + import com.hyperwallet.android.model.meta.Fee; import java.util.List; @@ -27,14 +29,15 @@ public class TransferMethodSelectionItem { private final String mCurrency; private final List mFees; private final String mProcessingTime; - private final String mProfile; + private final String mProfileType; private final String mTransferMethodType; - public TransferMethodSelectionItem(String country, String currency, String profile, String transferMethodType, - String processingTime, List fees) { + public TransferMethodSelectionItem(@NonNull final String country, @NonNull final String currency, + @NonNull final String profileType, @NonNull final String transferMethodType, + @NonNull final String processingTime, @NonNull final List fees) { mCountry = country; mCurrency = currency; - mProfile = profile; + mProfileType = profileType; mTransferMethodType = transferMethodType; mProcessingTime = processingTime; mFees = fees; @@ -48,8 +51,8 @@ public String getCurrency() { return mCurrency; } - public String getProfile() { - return mProfile; + public String getProfileType() { + return mProfileType; } public String getTransferMethodType() { @@ -71,12 +74,12 @@ public boolean equals(Object o) { TransferMethodSelectionItem that = (TransferMethodSelectionItem) o; return Objects.equals(mCountry, that.mCountry) && Objects.equals(mCurrency, that.mCurrency) && - Objects.equals(mProfile, that.mProfile) && + Objects.equals(mProfileType, that.mProfileType) && Objects.equals(mTransferMethodType, that.mTransferMethodType); } @Override public int hashCode() { - return Objects.hash(mCountry, mCurrency, mProfile, mTransferMethodType); + return Objects.hash(mCountry, mCurrency, mProfileType, mTransferMethodType); } } diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java index c89e2d298..ee6bd294e 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java @@ -13,6 +13,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static com.hyperwallet.android.model.HyperwalletUser.ProfileTypes.INDIVIDUAL; + import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.exception.HyperwalletException; import com.hyperwallet.android.listener.HyperwalletListener; @@ -168,7 +170,7 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.any(), ArgumentMatchers.>any()); - mTransferMethodConfigurationRepositoryImplMock.getFields(COUNTRY, CURRENCY, TRANSFER_METHOD_TYPE, + mTransferMethodConfigurationRepositoryImplMock.getFields(COUNTRY, CURRENCY, TRANSFER_METHOD_TYPE, INDIVIDUAL, loadFieldsCallback); verify(loadFieldsCallback).onFieldsLoaded(fieldResultArgumentCaptor.capture()); @@ -204,7 +206,7 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>any()); - mTransferMethodConfigurationRepositoryImplMock.getFields(COUNTRY, CURRENCY, TRANSFER_METHOD_TYPE, + mTransferMethodConfigurationRepositoryImplMock.getFields(COUNTRY, CURRENCY, TRANSFER_METHOD_TYPE, INDIVIDUAL, loadFieldsCallback); verify(loadFieldsCallback, never()).onFieldsLoaded( @@ -248,13 +250,14 @@ public void testGetFields_callsListenerWithFieldResultFromCacheWhenNotNull() thr FieldMapKey fieldMapKey = new FieldMapKey(COUNTRY, CURRENCY, TRANSFER_METHOD_TYPE); when(mFieldsMap.get(fieldMapKey)).thenReturn(result); - mTransferMethodConfigurationRepositoryImplMock.getFields(COUNTRY, CURRENCY, TRANSFER_METHOD_TYPE, + mTransferMethodConfigurationRepositoryImplMock.getFields(COUNTRY, CURRENCY, TRANSFER_METHOD_TYPE,INDIVIDUAL, loadFieldsCallback); verify(mTransferMethodConfigurationRepositoryImplMock, never()).getTransferMethodConfigurationFieldResult( any(String.class), any(String.class), any(String.class), + any(String.class), any(TransferMethodConfigurationRepository.LoadFieldsCallback.class)); verify(loadFieldsCallback).onFieldsLoaded(fieldResultArgumentCaptor.capture()); verify(loadFieldsCallback, never()).onError(any(HyperwalletErrors.class)); diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java b/ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java new file mode 100644 index 000000000..0f54ad10f --- /dev/null +++ b/ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java @@ -0,0 +1,197 @@ +package com.hyperwallet.android.ui.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.nullValue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import static com.hyperwallet.android.model.HyperwalletUser.ProfileTypes.INDIVIDUAL; +import static com.hyperwallet.android.model.HyperwalletUser.UserStatuses.PRE_ACTIVATED; +import static com.hyperwallet.android.model.HyperwalletUser.VerificationStatuses.NOT_REQUIRED; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.listener.HyperwalletListener; +import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.HyperwalletUser; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.stubbing.Answer; +import org.robolectric.RobolectricTestRunner; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class UserRepositoryImplTest { + @Mock + private Hyperwallet mHyperwallet; + @Mock + UserRepository.LoadUserCallback mMockCallback; + @Captor + private ArgumentCaptor mErrorCaptor; + @Captor + private ArgumentCaptor mUserCaptor; + @Rule + public MockitoRule mMockito = MockitoJUnit.rule(); + @Spy + UserRepositoryImpl mUserRepository; + + @Before + public void setup() { + doReturn(mHyperwallet).when(mUserRepository).getHyperwallet(); + } + + @Test + public void testLoadUser_returnsUser() { + HyperwalletUser.Builder builder = new HyperwalletUser.Builder(); + final HyperwalletUser user = builder + .token("usr-f9154016-94e8-4686-a840-075688ac07b5") + .status(PRE_ACTIVATED) + .verificationStatus(NOT_REQUIRED) + .createdOn("2017-10-30T22:15:45") + .clientUserId("123456") + .profileType(INDIVIDUAL) + .firstName("Some") + .lastName("Guy") + .dateOfBirth("1991-01-01") + .email("testUser@hyperwallet.com") + .addressLine1("575 Market Street") + .city("San Francisco") + .stateProvince("CA") + .country("US") + .postalCode("94105") + .language("en") + .programToken("prg-83836cdf-2ce2-4696-8bc5-f1b86077238c") + .build(); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[0]; + listener.onSuccess(user); + return listener; + } + }).when(mHyperwallet).getUser(ArgumentMatchers.>any()); + + mUserRepository.loadUser(mMockCallback); + + verify(mMockCallback).onUserLoaded(mUserCaptor.capture()); + verify(mMockCallback, never()).onError(any(HyperwalletErrors.class)); + + HyperwalletUser resultUser = mUserCaptor.getValue(); + assertThat(resultUser.getToken(), is("usr-f9154016-94e8-4686-a840-075688ac07b5")); + assertThat(resultUser.getStatus(), is(PRE_ACTIVATED)); + assertThat(resultUser.getVerificationStatus(), is(NOT_REQUIRED)); + assertThat(resultUser.getCreatedOn(), is("2017-10-30T22:15:45")); + assertThat(resultUser.getClientUserId(), is("123456")); + assertThat(resultUser.getProfileType(), is(INDIVIDUAL)); + assertThat(resultUser.getFirstName(), is("Some")); + assertThat(resultUser.getLastName(), is("Guy")); + assertThat(resultUser.getDateOfBirth(), is("1991-01-01")); + assertThat(resultUser.getEmail(), is("testUser@hyperwallet.com")); + assertThat(resultUser.getAddressLine1(), is("575 Market Street")); + assertThat(resultUser.getCity(), is("San Francisco")); + assertThat(resultUser.getStateProvince(), is("CA")); + assertThat(resultUser.getCountry(), is("US")); + assertThat(resultUser.getPostalCode(), is("94105")); + assertThat(resultUser.getLanguage(), is("en")); + assertThat(resultUser.getProgramToken(), is("prg-83836cdf-2ce2-4696-8bc5-f1b86077238c")); + } + + @Test + public void testLoadUser_returnsNoUser() { + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[0]; + listener.onSuccess(null); + return listener; + } + }).when(mHyperwallet).getUser(ArgumentMatchers.>any()); + + mUserRepository.loadUser(mMockCallback); + + verify(mMockCallback).onUserLoaded(mUserCaptor.capture()); + verify(mMockCallback, never()).onError(any(HyperwalletErrors.class)); + + HyperwalletUser user = mUserCaptor.getValue(); + assertThat(user, is(nullValue())); + } + + + @Test + public void testLoadUser_withError() { + + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[0]; + List errorList = new ArrayList<>(); + errorList.add(error); + HyperwalletErrors errors = new HyperwalletErrors(errorList); + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).getUser(ArgumentMatchers.>any()); + + mUserRepository.loadUser(mMockCallback); + + verify(mMockCallback, never()).onUserLoaded(ArgumentMatchers.any()); + verify(mMockCallback).onError(mErrorCaptor.capture()); + + assertThat(mErrorCaptor.getValue().getErrors(), hasItem(error)); + } + + @Test + public void testRefreshUser_verifyHyperwalletCallGetUser() { + HyperwalletUser.Builder builder = new HyperwalletUser.Builder(); + final HyperwalletUser user = builder + .token("usr-f9154016-94e8-4686-a840-075688ac07b5") + .profileType(INDIVIDUAL) + .build(); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[0]; + listener.onSuccess(user); + return listener; + } + }).when(mHyperwallet).getUser(ArgumentMatchers.>any()); + + mUserRepository.loadUser(mMockCallback); + + verify(mHyperwallet).getUser(ArgumentMatchers.>any()); + + mUserRepository.loadUser(mMockCallback); + verify(mHyperwallet).getUser(ArgumentMatchers.>any()); + + mUserRepository.refreshUser(); + mUserRepository.loadUser(mMockCallback); + verify(mHyperwallet, times(2)).getUser(ArgumentMatchers.>any()); + + } +} diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java index 4169726f8..a0f809ee0 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java @@ -13,6 +13,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static com.hyperwallet.android.model.HyperwalletUser.ProfileTypes.INDIVIDUAL; + import com.hyperwallet.android.model.HyperwalletBankAccount; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletErrors; @@ -149,15 +151,15 @@ public void testLoadTransferMethodConfigurationFields_loadsTransferMethodFieldsI @Override public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadFieldsCallback callback = - (TransferMethodConfigurationRepository.LoadFieldsCallback) invocation.getArguments()[3]; + (TransferMethodConfigurationRepository.LoadFieldsCallback) invocation.getArguments()[4]; callback.onFieldsLoaded(result); return callback; } - }).when(tmcRepository).getFields(anyString(), anyString(), anyString(), + }).when(tmcRepository).getFields(anyString(), anyString(), anyString(), anyString(), any(TransferMethodConfigurationRepository.LoadFieldsCallback.class)); // Then - presenter.loadTransferMethodConfigurationFields(false, "CA", "CAD", "BANK_ACCOUNT"); + presenter.loadTransferMethodConfigurationFields(false, "CA", "CAD", "BANK_ACCOUNT", INDIVIDUAL); LATCH.await(AWAIT_TIME_MS, TimeUnit.MILLISECONDS); verify(view).showTransferMethodFields(fieldArgumentCaptor.capture()); @@ -177,15 +179,15 @@ public void testLoadTransferMethodConfigurationFields_showsErrorOnFailure() thro @Override public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadFieldsCallback callback = - (TransferMethodConfigurationRepository.LoadFieldsCallback) invocation.getArguments()[3]; + (TransferMethodConfigurationRepository.LoadFieldsCallback) invocation.getArguments()[4]; callback.onError(errors); return callback; } - }).when(tmcRepository).getFields(anyString(), anyString(), anyString(), + }).when(tmcRepository).getFields(anyString(), anyString(), anyString(),anyString(), any(TransferMethodConfigurationRepository.LoadFieldsCallback.class)); // Then - presenter.loadTransferMethodConfigurationFields(false, "CA", "CAD", "BANK_ACCOUNT"); + presenter.loadTransferMethodConfigurationFields(false, "CA", "CAD", "BANK_ACCOUNT", INDIVIDUAL); LATCH.await(AWAIT_TIME_MS, TimeUnit.MILLISECONDS); verify(view, never()).showTransferMethodFields(ArgumentMatchers.anyList()); @@ -195,10 +197,10 @@ public Object answer(InvocationOnMock invocation) { @Test public void testLoadTransferMethodConfigurationFields_updatesFieldsWhenForceUpdateIsTrue() { - presenter.loadTransferMethodConfigurationFields(true, "CA", "CAD", "BANK_ACCOUNT"); + presenter.loadTransferMethodConfigurationFields(true, "CA", "CAD", "BANK_ACCOUNT", INDIVIDUAL); verify(tmcRepository, atLeastOnce()).refreshFields(); - verify(tmcRepository, atLeastOnce()).getFields(anyString(), anyString(), anyString(), + verify(tmcRepository, atLeastOnce()).getFields(anyString(), anyString(), anyString(), anyString(), any(TransferMethodConfigurationRepository.LoadFieldsCallback.class)); verify(view, never()).showTransferMethodFields(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadTransferMethodConfigurationFields( @@ -212,10 +214,10 @@ public void testLoadTransferMethodConfigurationFields_loadsTransferMethodFieldsI when(view.isActive()).thenReturn(false); // Then - presenter.loadTransferMethodConfigurationFields(true, "CA", "CAD", "BANK_ACCOUNT"); + presenter.loadTransferMethodConfigurationFields(true, "CA", "CAD", "BANK_ACCOUNT", INDIVIDUAL); verify(tmcRepository, atLeastOnce()).refreshFields(); - verify(tmcRepository, atLeastOnce()).getFields(anyString(), anyString(), anyString(), + verify(tmcRepository, atLeastOnce()).getFields(anyString(), anyString(), anyString(), anyString(), any(TransferMethodConfigurationRepository.LoadFieldsCallback.class)); verify(view, never()).hideProgressBar(); verify(view, never()).showTransferMethodFields(ArgumentMatchers.anyList()); @@ -232,15 +234,15 @@ public void testLoadTransferMethodConfigurationFields_loadsTransferMethodFieldsE @Override public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadFieldsCallback callback = - (TransferMethodConfigurationRepository.LoadFieldsCallback) invocation.getArguments()[3]; + (TransferMethodConfigurationRepository.LoadFieldsCallback) invocation.getArguments()[4]; callback.onError(errors); return callback; } - }).when(tmcRepository).getFields(anyString(), anyString(), anyString(), + }).when(tmcRepository).getFields(anyString(), anyString(), anyString(), anyString(), any(TransferMethodConfigurationRepository.LoadFieldsCallback.class)); // Then - presenter.loadTransferMethodConfigurationFields(false, "CA", "CAD", "BANK_ACCOUNT"); + presenter.loadTransferMethodConfigurationFields(false, "CA", "CAD", "BANK_ACCOUNT", INDIVIDUAL); LATCH.await(AWAIT_TIME_MS, TimeUnit.MILLISECONDS); verify(view, never()).hideProgressBar(); diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java index 5a666ec6e..6d1346ffd 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java @@ -13,9 +13,13 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.HyperwalletTransferMethod; +import com.hyperwallet.android.model.HyperwalletUser; import com.hyperwallet.android.model.meta.TransferMethodConfigurationResult; import com.hyperwallet.android.ui.repository.TransferMethodConfigurationRepository; import com.hyperwallet.android.ui.repository.TransferMethodConfigurationRepositoryImpl; +import com.hyperwallet.android.ui.repository.UserRepository; +import com.hyperwallet.android.ui.repository.UserRepositoryImpl; import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; import org.json.JSONObject; @@ -35,28 +39,36 @@ @RunWith(RobolectricTestRunner.class) public class SelectTransferMethodPresenterTest { - private static final String COUNTRY = "CA"; - private static final String CURRENCY = "CAD"; - private static final String BANK_ACCOUNT = "BANK_ACCOUNT"; + @Mock private SelectTransferMethodContract.View view; @Mock - private TransferMethodConfigurationRepositoryImpl transferMethodConfigurationRepository; + private TransferMethodConfigurationRepositoryImpl mTransferMethodConfigurationRepository; + @Mock + private UserRepositoryImpl mUserRepository; @Rule public HyperwalletExternalResourceManager externalResourceManager = new HyperwalletExternalResourceManager(); - private TransferMethodConfigurationResult result; + private TransferMethodConfigurationResult mResult; + private HyperwalletUser mUser; private SelectTransferMethodPresenter selectTransferMethodPresenter; private final HyperwalletErrors errors = createErrors(); @Before public void initialize() throws Exception { initMocks(this); - String responseBody = externalResourceManager.getResourceContent("successful_tmc_keys_response.json"); - final JSONObject jsonObject = new JSONObject(responseBody); - result = new TransferMethodConfigurationResult(jsonObject); - selectTransferMethodPresenter = new SelectTransferMethodPresenter(view, transferMethodConfigurationRepository); + + String methodsResponseBody = externalResourceManager.getResourceContent("successful_tmc_keys_response.json"); + final JSONObject methodsJsonObject = new JSONObject(methodsResponseBody); + mResult = new TransferMethodConfigurationResult(methodsJsonObject); + + String userResponseBody = externalResourceManager.getResourceContent("user_response.json"); + final JSONObject userJsonObject = new JSONObject(userResponseBody); + mUser = new HyperwalletUser(userJsonObject); + + selectTransferMethodPresenter = new SelectTransferMethodPresenter(view, mTransferMethodConfigurationRepository, + mUserRepository); } @Test @@ -69,12 +81,23 @@ public void testLoadTransferMethodConfigurationKeys_loadsKeysIntoViewOnSuccess() public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + // Then selectTransferMethodPresenter.loadTransferMethodConfigurationKeys(false, "CA", "CAD"); @@ -87,7 +110,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -100,12 +123,23 @@ public void testLoadTransferMethodConfigurationKeys_loadsKeysIntoViewOnSuccessIn public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + // Then selectTransferMethodPresenter.loadTransferMethodConfigurationKeys(false, "CA", "CAD"); @@ -117,7 +151,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -133,15 +167,26 @@ public Object answer(InvocationOnMock invocation) { callback.onError(errors); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + // Then selectTransferMethodPresenter.loadTransferMethodConfigurationKeys(false, "CA", "CAD"); verify(view, never()).showTransferMethodTypes(ArgumentMatchers.anyList()); verify(view).showErrorLoadTransferMethodConfigurationKeys(eq(errors.getErrors())); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -155,12 +200,23 @@ public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + // Then selectTransferMethodPresenter.loadCurrency(false, "CA"); @@ -172,7 +228,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); verify(view, atLeastOnce()).showTransferMethodCountry(anyString()); } @@ -187,11 +243,21 @@ public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); // Then selectTransferMethodPresenter.loadCurrency(false, "CA"); @@ -203,13 +269,13 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test public void testLoadCurrency_loadsCurrenciesWhenRefreshingKeys() { selectTransferMethodPresenter.loadCurrency(true, "CA"); - verify(transferMethodConfigurationRepository, times(1)).refreshKeys(); + verify(mTransferMethodConfigurationRepository, times(1)).refreshKeys(); } @@ -227,15 +293,26 @@ public Object answer(InvocationOnMock invocation) { callback.onError(errors); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + // Then selectTransferMethodPresenter.loadCurrency(false, "CA"); verify(view, never()).showTransferMethodTypes(ArgumentMatchers.anyList()); verify(view).showErrorLoadCurrency(eq(errors.getErrors())); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -249,14 +326,26 @@ public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + + // Then - selectTransferMethodPresenter.loadTransferMethodTypes(false, COUNTRY, CURRENCY); + selectTransferMethodPresenter.loadTransferMethodTypes(false, "CA", "CAD"); verify(view).showTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( @@ -265,7 +354,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); verify(view, atLeastOnce()).showTransferMethodCountry(anyString()); verify(view, atLeastOnce()).showTransferMethodCurrency(anyString()); } @@ -279,14 +368,26 @@ public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + + // Then - selectTransferMethodPresenter.loadTransferMethodTypes(false, COUNTRY, CURRENCY); + selectTransferMethodPresenter.loadTransferMethodTypes(false, "CA", "CAD"); verify(view, never()).showTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( @@ -295,7 +396,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -312,15 +413,26 @@ public Object answer(InvocationOnMock invocation) { callback.onError(errors); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + // Then selectTransferMethodPresenter.loadTransferMethodTypes(false, "CA", "CAD"); verify(view, never()).showTransferMethodTypes(ArgumentMatchers.anyList()); verify(view).showErrorLoadTransferMethodTypes(eq(errors.getErrors())); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -335,15 +447,26 @@ public Object answer(InvocationOnMock invocation) { callback.onError(errors); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + // Then selectTransferMethodPresenter.loadTransferMethodTypes(false, "CA", "CAD"); verify(view, never()).showTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadTransferMethodTypes(eq(errors.getErrors())); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -355,16 +478,18 @@ public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any(TransferMethodConfigurationRepository. + }).when(mTransferMethodConfigurationRepository).getKeys(any(TransferMethodConfigurationRepository. LoadKeysCallback.class)); // Then - selectTransferMethodPresenter.openAddTransferMethod(COUNTRY, CURRENCY, BANK_ACCOUNT); + selectTransferMethodPresenter.openAddTransferMethod("CA", "CAD", HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT, + HyperwalletUser.ProfileTypes.INDIVIDUAL); - verify(view).showAddTransferMethod(COUNTRY, CURRENCY, BANK_ACCOUNT); + verify(view).showAddTransferMethod("CA", "CAD", HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT, + HyperwalletUser.ProfileTypes.INDIVIDUAL); verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrency(ArgumentMatchers.anyList()); @@ -387,14 +512,14 @@ public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); // Then - selectTransferMethodPresenter.loadCountrySelection(COUNTRY); + selectTransferMethodPresenter.loadCountrySelection("CA"); verify(view).showCountrySelectionDialog(any(TreeMap.class), anyString()); verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( @@ -403,7 +528,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -415,14 +540,14 @@ public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); // Then - selectTransferMethodPresenter.loadCountrySelection(COUNTRY); + selectTransferMethodPresenter.loadCountrySelection("CA"); verify(view, never()).showCountrySelectionDialog(any(TreeMap.class), anyString()); verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( @@ -431,7 +556,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -448,15 +573,15 @@ public Object answer(InvocationOnMock invocation) { callback.onError(errors); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); // Then - selectTransferMethodPresenter.loadCountrySelection(COUNTRY); + selectTransferMethodPresenter.loadCountrySelection("CA"); verify(view, never()).showCountrySelectionDialog(any(TreeMap.class), anyString()); verify(view).showErrorLoadCountrySelection(eq(errors.getErrors())); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -471,11 +596,11 @@ public Object answer(InvocationOnMock invocation) { callback.onError(errors); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); // Then - selectTransferMethodPresenter.loadCountrySelection(COUNTRY); + selectTransferMethodPresenter.loadCountrySelection("CA"); verify(view, never()).showCountrySelectionDialog(any(TreeMap.class), anyString()); verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( @@ -484,7 +609,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -498,14 +623,14 @@ public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); // Then - selectTransferMethodPresenter.loadCurrencySelection(COUNTRY, CURRENCY); + selectTransferMethodPresenter.loadCurrencySelection("CA", "CAD"); verify(view).showCurrencySelectionDialog(any(TreeMap.class), anyString()); verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( @@ -514,7 +639,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -526,14 +651,14 @@ public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadKeysCallback callback = (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; - callback.onKeysLoaded(result); + callback.onKeysLoaded(mResult); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); // Then - selectTransferMethodPresenter.loadCurrencySelection(COUNTRY, CURRENCY); + selectTransferMethodPresenter.loadCurrencySelection("CA", "CAD"); verify(view, never()).showCurrencySelectionDialog(any(TreeMap.class), anyString()); verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( @@ -542,7 +667,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -559,15 +684,15 @@ public Object answer(InvocationOnMock invocation) { callback.onError(errors); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); // Then - selectTransferMethodPresenter.loadCurrencySelection(COUNTRY, CURRENCY); + selectTransferMethodPresenter.loadCurrencySelection("CA", "CAD"); verify(view, never()).showCurrencySelectionDialog(any(TreeMap.class), anyString()); verify(view).showErrorLoadCurrencySelection(eq(errors.getErrors())); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } @Test @@ -582,11 +707,11 @@ public Object answer(InvocationOnMock invocation) { callback.onError(errors); return callback; } - }).when(transferMethodConfigurationRepository).getKeys(any( + }).when(mTransferMethodConfigurationRepository).getKeys(any( TransferMethodConfigurationRepository.LoadKeysCallback.class)); // Then - selectTransferMethodPresenter.loadCurrencySelection(COUNTRY, CURRENCY); + selectTransferMethodPresenter.loadCurrencySelection("CA", "CAD"); verify(view, never()).showCurrencySelectionDialog(any(TreeMap.class), anyString()); verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( @@ -595,7 +720,7 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); - verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } private HyperwalletErrors createErrors() { @@ -604,4 +729,50 @@ private HyperwalletErrors createErrors() { errors.add(error); return new HyperwalletErrors(errors); } + + @Test + public void testLoadMethods_whenLoadUserWithError_checkShowingErrors() { + + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + List errorList = new ArrayList<>(); + errorList.add(error); + final HyperwalletErrors errors = new HyperwalletErrors(errorList); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onError(errors); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + when(view.isActive()).thenReturn(false); + // Then + selectTransferMethodPresenter.loadTransferMethodConfigurationKeys(false, "CA", "CAD"); + + verify(view, never()).showErrorLoadTransferMethodConfigurationKeys(ArgumentMatchers.anyList()); + + selectTransferMethodPresenter.loadCurrency(false, "CA"); + verify(view, never()).showErrorLoadCurrency(ArgumentMatchers.anyList()); + + selectTransferMethodPresenter.loadTransferMethodTypes(false, "CA", "CAD"); + verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); + + + // When + when(view.isActive()).thenReturn(true); + + // Then + selectTransferMethodPresenter.loadTransferMethodConfigurationKeys(false, "CA", "CAD"); + + verify(view).showErrorLoadTransferMethodConfigurationKeys(ArgumentMatchers.anyList()); + + selectTransferMethodPresenter.loadCurrency(false, "CA"); + verify(view).showErrorLoadCurrency(ArgumentMatchers.anyList()); + + selectTransferMethodPresenter.loadTransferMethodTypes(false, "CA", "CAD"); + verify(view).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); + } } diff --git a/ui/src/test/resources/user_business_response.json b/ui/src/test/resources/user_business_response.json new file mode 100644 index 000000000..5ba6c60e2 --- /dev/null +++ b/ui/src/test/resources/user_business_response.json @@ -0,0 +1,44 @@ +{ + "token": "usr-e602a937-334c-49e5-b37e-4c842c1cc7a1", + "status": "PRE_ACTIVATED", + "verificationStatus": "NOT_REQUIRED", + "createdOn": "2019-05-14T21:51:15", + "clientUserId": "testUserCIQlsWTo0BOQ", + "profileType": "BUSINESS", + "businessType": "CORPORATION", + "businessName": "Alana LTD", + "businessRegistrationId": "1234", + "businessRegistrationStateProvince": "BCA", + "businessRegistrationCountry": "CA", + "businessContactRole": "OTHER", + "firstName": "Bevis", + "middleName": "Kylynn", + "lastName": "Pace", + "dateOfBirth": "2001-01-01", + "countryOfBirth": "US", + "countryOfNationality": "FR", + "gender": "FEMALE", + "phoneNumber": "604-345-1777", + "mobileNumber": "604-345-1888", + "email": "lizeth.mazzotta@fullmail.com", + "governmentId": "999000999", + "passportId": "123456789", + "driversLicenseId": "234234243", + "addressLine1": "838 7th ave", + "addressLine2": "second floor", + "city": "Burnaby", + "stateProvince": "XZ", + "country": "CA", + "postalCode": "v5z3a2", + "language": "en", + "timeZone": "GMT", + "programToken": "prg-7a2441be-1b00-4239-b2d6-623a0eb8f160", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://api.sandbox.hyperwallet.com/rest/v3/users/usr-e602a937-334c-49e5-b37e-4c842c1cc7a1" + } + ] +} \ No newline at end of file diff --git a/ui/src/test/resources/user_response.json b/ui/src/test/resources/user_response.json new file mode 100644 index 000000000..e65074bef --- /dev/null +++ b/ui/src/test/resources/user_response.json @@ -0,0 +1,26 @@ +{ + "token": "usr-f9154016-94e8-4686-a840-075688ac07b5", + "status": "PRE_ACTIVATED", + "createdOn": "2017-10-30T22:15:45", + "clientUserId": "123456", + "profileType": "INDIVIDUAL", + "firstName": "Some", + "lastName": "Guy", + "dateOfBirth": "1991-01-01", + "email": "user+4satF1xV@hyperwallet.com", + "addressLine1": "575 Market Street", + "city": "San Francisco", + "stateProvince": "CA", + "country": "US", + "postalCode": "94105", + "language": "en", + "programToken": "prg-83836cdf-2ce2-4696-8bc5-f1b86077238c", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://api.sandbox.hyperwallet.com/rest/v3/users/usr-f9154016-94e8-4686-a840-075688ac07b5" + } + ] +} \ No newline at end of file From 2ca4fcad724acd22a56f44f665717cd8d6231d6b Mon Sep 17 00:00:00 2001 From: Flavio Mattos Date: Wed, 15 May 2019 12:52:04 -0700 Subject: [PATCH 005/177] bump dev version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index aa5a21068..c8bea05e8 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ allprojects { } - project.version = "1.0.0-beta02"; + project.version = "1.0.0-beta03-SNAPSHOT"; } task clean(type: Delete) { From a55e0feed03d01be14ee9690a21b9e19eff9e872 Mon Sep 17 00:00:00 2001 From: Peter Joseph Olamit Date: Wed, 22 May 2019 14:42:58 -0700 Subject: [PATCH 006/177] Epic/HW-52169 gql version two integration (#24) --- build.gradle | 3 +- ui/build.gradle | 4 +- .../ui/AddTransferMethodTest.java | 6 +- .../transfermethod/ui/BankAccountTest.java | 185 +- .../transfermethod/ui/BankCardTest.java | 30 +- .../android/transfermethod/ui/PayPalTest.java | 23 +- .../ui/SelectTransferMethodTest.java | 58 +- .../android/util/EspressoUtils.java | 20 + ...TransferMethodConfigurationRepository.java | 14 +- ...sferMethodConfigurationRepositoryImpl.java | 73 +- .../repository/TransferMethodRepository.java | 4 +- .../TransferMethodRepositoryImpl.java | 2 +- .../AddTransferMethodContract.java | 8 +- .../AddTransferMethodFragment.java | 111 +- .../AddTransferMethodPresenter.java | 19 +- .../ui/transfermethod/FeeFormatter.java | 34 +- .../ListTransferMethodPresenter.java | 2 +- .../SelectTransferMethodFragment.java | 6 +- .../SelectTransferMethodPresenter.java | 116 +- .../TransferMethodSelectionItem.java | 19 +- .../view/WidgetSelectionDialogFragment.java | 92 +- .../ui/view/widget/AbstractWidget.java | 38 +- .../android/ui/view/widget/DateWidget.java | 30 +- .../ui/view/widget/DefaultAccountWidget.java | 23 +- .../ui/view/widget/ExpiryDateWidget.java | 43 +- .../android/ui/view/widget/NumberWidget.java | 29 +- .../android/ui/view/widget/PhoneWidget.java | 30 +- .../ui/view/widget/SelectionWidget.java | 63 +- .../android/ui/view/widget/TextWidget.java | 31 +- .../android/ui/view/widget/WidgetFactory.java | 15 +- .../layout/fragment_add_transfer_method.xml | 15 - ui/src/main/res/layout/item_widget_layout.xml | 10 + .../res/layout/item_widget_section_header.xml | 15 + .../main/res/menu/menu_widget_selection.xml | 10 + ui/src/main/res/values/dimens.xml | 4 + ui/src/main/res/values/ids.xml | 82 + ui/src/main/res/values/strings.xml | 16 +- ui/src/main/res/values/styles.xml | 11 + ...MethodConfigurationRepositoryImplTest.java | 92 +- .../TransferMethodRepositoryImplTest.java | 6 +- .../ui/repository/UserRepositoryImplTest.java | 1 - .../AddTransferMethodPresenterTest.java | 37 +- .../ui/transfermethod/FeeFormatterTest.java | 70 +- .../ListTransferMethodPresenterTest.java | 20 +- .../SelectTransferMethodPresenterTest.java | 21 +- .../add_transfer_method_presenter_test.json | 37 +- .../test/resources/bank_account_response.json | 6 +- ui/src/test/resources/fee_information.json | 77 + ...cessful_tmc_bank_card_fields_response.json | 84 - ...sful_tmc_fields_bank_account_response.json | 1240 ++ ...cessful_tmc_fields_bank_card_response.json | 1124 + ...ful_tmc_fields_empty_details_response.json | 1279 +- ...successful_tmc_fields_paypal_response.json | 1193 + .../successful_tmc_fields_response.json | 87 - ...uccessful_tmc_keys_empty_fee_response.json | 41 +- ...ul_tmc_keys_empty_processing_response.json | 61 +- .../successful_tmc_keys_large_response.json | 18238 ++++++---------- .../successful_tmc_keys_response.json | 396 +- ...successful_tmc_paypal_fields_response.json | 46 - 59 files changed, 13217 insertions(+), 12233 deletions(-) create mode 100644 ui/src/main/res/layout/item_widget_layout.xml create mode 100644 ui/src/main/res/layout/item_widget_section_header.xml create mode 100644 ui/src/main/res/menu/menu_widget_selection.xml create mode 100644 ui/src/test/resources/fee_information.json delete mode 100644 ui/src/test/resources/successful_tmc_bank_card_fields_response.json create mode 100644 ui/src/test/resources/successful_tmc_fields_bank_account_response.json create mode 100644 ui/src/test/resources/successful_tmc_fields_bank_card_response.json create mode 100644 ui/src/test/resources/successful_tmc_fields_paypal_response.json delete mode 100644 ui/src/test/resources/successful_tmc_fields_response.json delete mode 100644 ui/src/test/resources/successful_tmc_paypal_fields_response.json diff --git a/build.gradle b/build.gradle index c8bea05e8..7d443fbbc 100644 --- a/build.gradle +++ b/build.gradle @@ -23,8 +23,7 @@ allprojects { mavenLocal() } - - project.version = "1.0.0-beta03-SNAPSHOT"; + project.version = "1.0.0-beta03-SNAPSHOT" } task clean(type: Delete) { diff --git a/ui/build.gradle b/ui/build.gradle index 36be7e3cb..36e57ea3a 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -49,7 +49,7 @@ dependencies { implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.recyclerview:recyclerview:1.0.0" - api 'com.hyperwallet.android:core-sdk:1.0.0-beta02' + api "com.hyperwallet.android:core-sdk:1.0.0-beta03-SNAPSHOT" androidTestImplementation "androidx.test.ext:junit:1.1.0" androidTestImplementation "androidx.test:runner:1.1.1" @@ -61,7 +61,7 @@ dependencies { androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:1.6.3" androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:1.6.3" - testImplementation group: 'org.mockito', name: 'mockito-core', version: "2.23.4" + testImplementation group: 'org.mockito', name: 'mockito-core', version: "2.25.0" testImplementation group: 'pl.pragmatists', name: 'JUnitParams', version: "1.1.1" testImplementation "org.robolectric:robolectric:4.1" testImplementation "com.squareup.okhttp3:mockwebserver:3.11.0" diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java index 914cfde4a..c4af970ff 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java @@ -124,7 +124,7 @@ public void testAddTransferMethod_accountDetailsHiddenOnEmptyFeeAndProcessingRes @Test public void testAddTransferMethod_displaysErrorDialogOnDuplicateAccountFailure() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_bank_account_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_BAD_REQUEST).withBody(sResourceManager .getResourceContent("bank_account_duplicate_routing_response.json")).mock(); @@ -159,7 +159,7 @@ public void testAddTransferMethod_displaysErrorDialogOnDuplicateAccountFailure() @Test public void testAddTransferMethod_displaysUnexpectedErrorDialogOnException() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_bank_account_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_BAD_REQUEST).withBody(sResourceManager .getResourceContent("invalid_json_response.json")).mock(); @@ -189,7 +189,7 @@ public void testAddTransferMethod_displaysUnexpectedErrorDialogOnException() { @Test public void testAddTransferMethod_displaysNetworkErrorDialogOnConnectionTimeout() throws IOException { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_bank_account_response.json")).mock(); mActivityTestRule.launchActivity(null); diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java index 3a48ac15e..9134735a2 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java @@ -7,7 +7,9 @@ import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; +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; @@ -16,6 +18,7 @@ import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; import static java.net.HttpURLConnection.HTTP_CREATED; @@ -23,6 +26,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static com.hyperwallet.android.model.HyperwalletBankAccount.Purpose.SAVINGS; +import static com.hyperwallet.android.util.EspressoUtils.hasEmptyText; import static com.hyperwallet.android.util.EspressoUtils.hasErrorText; import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; import static com.hyperwallet.android.util.EspressoUtils.withHint; @@ -37,6 +41,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.test.core.app.ApplicationProvider; import androidx.test.espresso.IdlingRegistry; +import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ActivityTestRule; @@ -63,9 +68,6 @@ @RunWith(AndroidJUnit4.class) public class BankAccountTest { - private static final String ACCOUNT_NUMBER_LABEL = "Account Number"; - private static final String ROUTING_NUMBER_LABEL = "Routing Number"; - private static final String ACCOUNT_TYPE_LABEL = "Account Type"; private static final String ACCOUNT_NUMBER = "8017110254"; private static final String ROUTING_NUMBER = "211179539"; private static final String INVALID_ROUTING_NUMBER = "211179531"; @@ -96,7 +98,7 @@ public void setup() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("authentication_token_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_bank_account_response.json")).mock(); } @After @@ -118,31 +120,133 @@ public void unregisterIdlingResource() { public void testAddTransferMethod_displaysElementsOnTmcResponse() { mActivityTestRule.launchActivity(null); - onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))).check( - matches(withText(R.string.title_add_bank_account))); - - onView(withId(R.id.branchId)).check(matches(isDisplayed())); - onView(withId(R.id.branchIdLabel)).check(matches(withHint(ROUTING_NUMBER_LABEL))); - onView(withId(R.id.bankAccountId)).check(matches(isDisplayed())); - onView(withId(R.id.bankAccountIdLabel)).check(matches(withHint(ACCOUNT_NUMBER_LABEL))); - onView(withId(R.id.bankAccountPurpose)).check(matches(isDisplayed())); + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_add_bank_account))); + + onView(allOf(withId(R.id.section_header_title), withText("Account Information - United States (USD)"))).check( + matches(isDisplayed())); + onView(withId(R.id.branchId)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.branchIdLabel)).check(matches(isDisplayed())); + onView(withId(R.id.branchIdLabel)).check(matches(withHint("Routing Number"))); + onView(withId(R.id.bankAccountId)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.bankAccountIdLabel)).check(matches(isDisplayed())); + onView(withId(R.id.bankAccountIdLabel)).check(matches(withHint("Account Number"))); + onView(withId(R.id.bankAccountPurpose)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.bankAccountPurposeLabel)).check(matches(isDisplayed())); onView(withId(R.id.bankAccountPurposeLabel)).check( - matches(withHint(ACCOUNT_TYPE_LABEL))); - - onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo()).check( - matches(withText(R.string.button_create_transfer_method))); + matches(withHint("Account Type"))); + + onView(allOf(withId(R.id.section_header_title), withText("Account Holder"))).perform(nestedScrollTo()).check( + matches(isDisplayed())); + onView(withId(R.id.firstName)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.firstNameLabel)).check(matches(isDisplayed())); + onView(withId(R.id.firstNameLabel)).check(matches(withHint("First Name"))); + onView(withId(R.id.middleName)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.middleNameLabel)).check(matches(isDisplayed())); + onView(withId(R.id.middleNameLabel)).check(matches(withHint("Middle Name"))); + onView(withId(R.id.lastName)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.lastNameLabel)).check(matches(isDisplayed())); + onView(withId(R.id.lastNameLabel)).check(matches(withHint("Last Name"))); + onView(withId(R.id.dateOfBirth)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.dateOfBirthLabel)).check(matches(isDisplayed())); + onView(withId(R.id.dateOfBirthLabel)).check(matches(withHint("Date of Birth"))); + + onView(allOf(withId(R.id.section_header_title), withText("Contact Information"))).perform( + nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.phoneNumber)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.phoneNumberLabel)).check(matches(isDisplayed())); + onView(withId(R.id.phoneNumberLabel)).check(matches(withHint("Phone Number"))); + onView(withId(R.id.mobileNumber)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.mobileNumberLabel)).check(matches(isDisplayed())); + onView(withId(R.id.mobileNumberLabel)).check(matches(withHint("Mobile Number"))); + + onView(allOf(withId(R.id.section_header_title), withText("Address"))).perform(nestedScrollTo()).check( + matches(isDisplayed())); + onView(withId(R.id.country)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.countryLabel)).check(matches(isDisplayed())); + onView(withId(R.id.countryLabel)).check(matches(withHint("Country"))); + onView(withId(R.id.stateProvince)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.stateProvinceLabel)).check(matches(isDisplayed())); + onView(withId(R.id.stateProvinceLabel)).check(matches(withHint("State/Province"))); + onView(withId(R.id.addressLine1)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.addressLine1Label)).check(matches(isDisplayed())); + onView(withId(R.id.addressLine1Label)).check(matches(withHint("Street"))); + onView(withId(R.id.city)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.cityLabel)).check(matches(isDisplayed())); + onView(withId(R.id.cityLabel)).check(matches(withHint("City"))); + onView(withId(R.id.postalCode)).perform(nestedScrollTo()).check(matches(isDisplayed())); + onView(withId(R.id.postalCodeLabel)).check(matches(isDisplayed())); + onView(withId(R.id.postalCodeLabel)).check(matches(withHint("Zip/Postal Code"))); + + onView(withId(R.id.add_transfer_method_button)) + .perform(nestedScrollTo()).check(matches(withText(R.string.button_create_transfer_method))); } @Test public void testAddTransferMethod_displaysFeeElementsOnTmcResponse() { mActivityTestRule.launchActivity(null); + onView(withId(R.id.add_transfer_method_static_container)) + .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); + + onView(withId(R.id.add_transfer_method_fee_label)) + .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); onView(withId(R.id.add_transfer_method_fee_label)).check( matches(withText(R.string.add_transfer_method_fee_label))); - onView(withId(R.id.add_transfer_method_processing_label)).check( - matches(withText(R.string.add_transfer_method_processing_time_label))); onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("USD 2.00"))); - onView(withId(R.id.add_transfer_method_processing_time_value)).check(matches(withText("1-2 Business days"))); + + //TODO: Uncomment when processing time node is implemented +// onView(withId(R.id.add_transfer_method_processing_label)).check( +// matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); +// onView(withId(R.id.add_transfer_method_processing_label)).check( +// matches(withText(R.string.add_transfer_method_processing_time_label))); +// onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("1 - 2 Business Days"))); + } + + @Test + public void testAddTransferMethod_verifyDefaultValues() { + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.branchId)).check(matches(hasEmptyText())); + onView(withId(R.id.bankAccountId)).check(matches(hasEmptyText())); + onView(withId(R.id.bankAccountPurpose)).check(matches(hasEmptyText())); + + onView(withId(R.id.firstName)).check(matches(withText("Brody"))); + onView(withId(R.id.middleName)).check(matches(hasEmptyText())); + onView(withId(R.id.lastName)).check(matches(withText("Nehru"))); + onView(withId(R.id.dateOfBirth)).check(matches(withText("2000-01-01"))); + + onView(withId(R.id.phoneNumber)).check(matches(withText("+1 604 6666666"))); + onView(withId(R.id.mobileNumber)).check(matches(withText("604 666 6666"))); + + onView(withId(R.id.country)).check(matches(withText("Canada"))); + onView(withId(R.id.stateProvince)).check(matches(withText("BC"))); + onView(withId(R.id.addressLine1)).check(matches(withText("950 Granville Street"))); + onView(withId(R.id.city)).check(matches(withText("Vancouver"))); + onView(withId(R.id.postalCode)).check(matches(withText("V6Z1L2"))); + } + + @Test + public void testAddTransferMethod_verifyEditableFields() { + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.branchId)).check(matches(isEnabled())); + onView(withId(R.id.bankAccountId)).check(matches(isEnabled())); + onView(withId(R.id.bankAccountPurpose)).check(matches(isEnabled())); + + onView(withId(R.id.firstName)).check(matches(not(isEnabled()))); + onView(withId(R.id.middleName)).check(matches(isEnabled())); + onView(withId(R.id.lastName)).check(matches(isEnabled())); + onView(withId(R.id.dateOfBirth)).check(matches(isEnabled())); + + onView(withId(R.id.phoneNumber)).check(matches(isEnabled())); + onView(withId(R.id.mobileNumber)).check(matches(isEnabled())); + + onView(withId(R.id.country)).check(matches(not(isEnabled()))); + onView(withId(R.id.stateProvince)).check(matches(isEnabled())); + onView(withId(R.id.addressLine1)).check(matches(isEnabled())); + onView(withId(R.id.city)).check(matches(isEnabled())); + onView(withId(R.id.postalCode)).check(matches(isEnabled())); } @Test @@ -166,6 +270,28 @@ public void onReceive(Context context, Intent intent) { HyperwalletTransferMethod.TransferMethodFields.BRANCH_ID), is(ROUTING_NUMBER)); assertThat("Bank Account purpose is incorrect", transferMethod.getField( HyperwalletTransferMethod.TransferMethodFields.BANK_ACCOUNT_PURPOSE), is(SAVINGS)); + + assertThat("First Name is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.FIRST_NAME), is("Brody")); + assertThat("Last Name is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.LAST_NAME), is("Nehru")); + assertThat("Date of birth is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.DATE_OF_BIRTH), is("2000-01-01")); + + assertThat("Phone Number is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.PHONE_NUMBER), is("+1 604 6666666")); + assertThat("Mobile Number incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.MOBILE_NUMBER), is("604 666 6666")); + assertThat("Country is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.COUNTRY), is("CA")); + assertThat("State Province is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.STATE_PROVINCE), is("BC")); + assertThat("Address is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.ADDRESS_LINE_1), is("950 Granville Street")); + assertThat("City is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.CITY), is("Vancouver")); + assertThat("Postal Code is incorrect", transferMethod.getField( + HyperwalletTransferMethod.TransferMethodFields.POSTAL_CODE), is("V6Z1L2")); } }; @@ -173,11 +299,9 @@ public void onReceive(Context context, Intent intent) { .registerReceiver(br, new IntentFilter("ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED")); onView(withId(R.id.branchId)) - .perform(typeText(ROUTING_NUMBER)) - .perform(closeSoftKeyboard()); + .perform(typeText(ROUTING_NUMBER)).perform(closeSoftKeyboard()); onView(withId(R.id.bankAccountId)) - .perform(typeText(ACCOUNT_NUMBER)) - .perform(closeSoftKeyboard()); + .perform(typeText(ACCOUNT_NUMBER)).perform(closeSoftKeyboard()); onView(withId(R.id.bankAccountPurpose)).perform(click()); onView(withId(R.id.search_button)).check(doesNotExist()); onView(withId(R.id.input_selection_list)).check(new RecyclerViewCountAssertion(2)); @@ -211,17 +335,16 @@ public void testAddTransferMethod_returnsErrorOnInvalidPresence() { onView(withId(R.id.bankAccountPurpose)).perform(click()); onView(allOf(withContentDescription(R.string.abc_action_bar_up_description), - withParent(withId(R.id.input_selection_toolbar)))).perform( - click()); + withParent(withId(R.id.input_selection_toolbar)))).perform(click()); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); onView(withId(R.id.branchIdLabel)) - .check(matches(hasErrorText("You must provide a value for this field."))); + .check(matches(hasErrorText("You must provide a value for this field"))); onView(withId(R.id.bankAccountIdLabel)) - .check(matches(hasErrorText("You must provide a value for this field."))); + .check(matches(hasErrorText("You must provide a value for this field"))); onView(withId(R.id.bankAccountPurposeLabel)) - .check(matches(hasErrorText("You must provide a value for this field."))); + .check(matches(hasErrorText("You must provide a value for this field"))); } @Test @@ -229,11 +352,9 @@ public void testAddTransferMethod_returnsErrorOnInvalidLength() { mActivityTestRule.launchActivity(null); onView(withId(R.id.branchId)) - .perform(typeText("2111795311")) - .perform(closeSoftKeyboard()); + .perform(typeText("2111795311")).perform(closeSoftKeyboard()); onView(withId(R.id.bankAccountId)) - .perform(typeText("1")) - .perform(closeSoftKeyboard()); + .perform(typeText("1")).perform(closeSoftKeyboard()); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java index 8f05f330d..e2d2c1003 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java @@ -7,6 +7,7 @@ import static androidx.test.espresso.action.ViewActions.typeText; import static androidx.test.espresso.assertion.ViewAssertions.matches; 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; @@ -35,6 +36,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.test.core.app.ApplicationProvider; import androidx.test.espresso.IdlingRegistry; +import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ActivityTestRule; @@ -98,7 +100,7 @@ public void setup() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("authentication_token_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_bank_card_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_bank_card_response.json")).mock(); } @After @@ -124,12 +126,14 @@ public void testAddTransferMethod_displaysElementsOnTmcResponse() { matches(withText(R.string.title_add_bank_card))); onView(withId(R.id.cardNumber)).check(matches(isDisplayed())); + onView(withId(R.id.cardNumberLabel)).check(matches(isDisplayed())); onView(withId(R.id.cardNumberLabel)).check(matches(withHint(CARD_NUMBER_LABEL))); onView(withId(R.id.dateOfExpiry)).check(matches(isDisplayed())); + onView(withId(R.id.dateOfExpiryLabel)).check(matches(isDisplayed())); onView(withId(R.id.dateOfExpiryLabel)).check(matches(withHint(EXPIRY_DATE_LABEL))); onView(withId(R.id.cvv)).check(matches(isDisplayed())); - onView(withId(R.id.cvvLabel)).check( - matches(withHint(CVV_LABEL))); + onView(withId(R.id.cvvLabel)).check(matches(isDisplayed())); + onView(withId(R.id.cvvLabel)).check(matches(withHint(CVV_LABEL))); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo()).check( matches(withText(R.string.button_create_transfer_method))); @@ -139,11 +143,21 @@ public void testAddTransferMethod_displaysElementsOnTmcResponse() { public void testAddTransferMethod_displaysFeeElementsOnTmcResponse() { mActivityTestRule.launchActivity(null); + onView(withId(R.id.add_transfer_method_static_container)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); + + onView(withId(R.id.add_transfer_method_fee_label)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); onView(withId(R.id.add_transfer_method_fee_label)).check( matches(withText(R.string.add_transfer_method_fee_label))); - onView(withId(R.id.add_transfer_method_processing_label)).check( - matches(withText(R.string.add_transfer_method_processing_time_label))); onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("USD 1.75"))); + + //TODO: Uncomment when processing time node is implemented +// onView(withId(R.id.add_transfer_method_processing_label)).check( +// matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); +// onView(withId(R.id.add_transfer_method_processing_label)).check( +// matches(withText(R.string.add_transfer_method_processing_time_label))); +// onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("1 - 2 Business Days"))); } @Test @@ -211,11 +225,11 @@ public void testAddTransferMethod_returnsErrorOnInvalidPresence() { onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); onView(withId(R.id.cardNumberLabel)) - .check(matches(hasErrorText("You must provide a value for this field."))); + .check(matches(hasErrorText("You must provide a value for this field"))); onView(withId(R.id.dateOfExpiryLabel)) - .check(matches(hasErrorText("You must provide a value for this field."))); + .check(matches(hasErrorText("You must provide a value for this field"))); onView(withId(R.id.cvvLabel)) - .check(matches(hasErrorText("You must provide a value for this field."))); + .check(matches(hasErrorText("You must provide a value for this field"))); } @Test diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java index 6bf0ec8bd..0133e6a90 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java @@ -8,6 +8,7 @@ import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.RootMatchers.isDialog; 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; @@ -37,6 +38,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.test.core.app.ApplicationProvider; import androidx.test.espresso.IdlingRegistry; +import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ActivityTestRule; @@ -88,7 +90,7 @@ public void setup() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("authentication_token_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_paypal_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_paypal_response.json")).mock(); } @After @@ -114,6 +116,7 @@ public void testAddTransferMethod_displaysElementsOnTmcResponse() { matches(withText(R.string.paypal_account))); onView(withId(R.id.email)).check(matches(isDisplayed())); + onView(withId(R.id.emailLabel)).check(matches(isDisplayed())); onView(withId(R.id.emailLabel)).check(matches(withHint("Email"))); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo()).check( @@ -124,12 +127,22 @@ public void testAddTransferMethod_displaysElementsOnTmcResponse() { public void testAddTransferMethod_displaysFeeElementsOnTmcResponse() { mActivityTestRule.launchActivity(null); + onView(withId(R.id.add_transfer_method_static_container)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); + + onView(withId(R.id.add_transfer_method_fee_label)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); onView(withId(R.id.add_transfer_method_fee_label)).check( matches(withText(R.string.add_transfer_method_fee_label))); - onView(withId(R.id.add_transfer_method_processing_label)).check( - matches(withText(R.string.add_transfer_method_processing_time_label))); onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("USD 0.25"))); - onView(withId(R.id.add_transfer_method_processing_time_value)).check(matches(withText("IMMEDIATE"))); + + //TODO: Uncomment when processing time node is implemented +// onView(withId(R.id.add_transfer_method_processing_label)).check( +// matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); +// onView(withId(R.id.add_transfer_method_processing_label)).check( +// matches(withText(R.string.add_transfer_method_processing_time_label))); +// onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("IMMEDIATE"))); + } @Test @@ -178,7 +191,7 @@ public void testAddTransferMethod_returnsErrorOnInvalidPattern() { onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); onView(withId(R.id.emailLabel)) - .check(matches(hasErrorText("accountNumber is invalid"))); + .check(matches(hasErrorText("is invalid length or format."))); } @Test diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java index 018556a36..01aa039f7 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java @@ -136,9 +136,13 @@ public void testSelectTransferMethod_verifyCountrySelectionList() { onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.country_selection_toolbar)))).check( matches(withText(R.string.select_transfer_method_country))); onView(withId(R.id.search_button)).check(doesNotExist()); - onView(withId(R.id.country_selection_list)).check(new RecyclerViewCountAssertion(2)); + onView(withId(R.id.country_selection_list)).check(new RecyclerViewCountAssertion(5)); onView(allOf(withId(R.id.country_name), withText("Canada"))).check(matches(isDisplayed())); + onView(allOf(withId(R.id.country_name), withText("Croatia"))).check(matches(isDisplayed())); + onView(allOf(withId(R.id.country_name), withText("Mexico"))).check(matches(isDisplayed())); + onView(allOf(withId(R.id.country_name), withText("United Kingdom"))).check(matches(isDisplayed())); onView(allOf(withId(R.id.country_name), withText("United States"))).check(matches(isDisplayed())); + onView(allOf(withId(R.id.country_item_selected_image), hasSibling(allOf(withId(R.id.country_name), withText("United States"))))).check(matches(isDisplayed())); @@ -185,11 +189,12 @@ public void testSelectTransferMethod_verifyCurrencySelectionList() { matches(withText(R.string.select_transfer_method_currency))); onView(withId(R.id.search_button)).check(doesNotExist()); onView(withId(R.id.currency_selection_list)).check(new RecyclerViewCountAssertion(1)); - onView(allOf(withId(R.id.currency_name), withText("US Dollar"))).check(matches(isDisplayed())); + onView(allOf(withId(R.id.currency_name), withText("United States Dollar"))).check(matches(isDisplayed())); onView(allOf(withId(R.id.currency_item_selected_image), - hasSibling(allOf(withId(R.id.currency_name), withText("US Dollar"))))).check(matches(isDisplayed())); + hasSibling(allOf(withId(R.id.currency_name), withText("United States Dollar"))))).check( + matches(isDisplayed())); - onView(allOf(withId(R.id.currency_name), withText("US Dollar"))).perform(click()); + onView(allOf(withId(R.id.currency_name), withText("United States Dollar"))).perform(click()); onView(withId(R.id.select_transfer_method_currency_value)).check(matches(withText("USD"))); } @@ -204,7 +209,7 @@ public void testSelectTransferMethod_verifyTransferMethodsList() { onView(withId(R.id.select_transfer_method_country_value)).check(matches(withText("United States"))); onView(withId(R.id.select_transfer_method_currency_value)).check(matches(withText("USD"))); - onView(withId(R.id.select_transfer_method_types_list)).check(new RecyclerViewCountAssertion(2)); + onView(withId(R.id.select_transfer_method_types_list)).check(new RecyclerViewCountAssertion(4)); onView(withId(R.id.select_transfer_method_types_list)).check( matches(atPosition(0, hasDescendant(withText(R.string.bank_account_font_icon))))); @@ -222,6 +227,24 @@ public void testSelectTransferMethod_verifyTransferMethodsList() { onView(withId(R.id.select_transfer_method_types_list)).check( matches(atPosition(1, hasDescendant(withText("Transaction Fee: USD 1.75"))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(2, hasDescendant(withText(R.string.wire_account_font_icon))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(2, hasDescendant(withText(R.string.wire_account))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(2, hasDescendant(withText("Transaction Fee: USD 20.00"))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(2, hasDescendant(withText("Processing Time: 1-3 Business days"))))); + + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(3, hasDescendant(withText(R.string.paypal_account_font_icon))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(3, hasDescendant(withText(R.string.paypal_account))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(3, hasDescendant(withText("Transaction Fee: USD 0.25"))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(3, hasDescendant(withText("Processing Time: IMMEDIATE"))))); + } @Test @@ -283,20 +306,29 @@ public void testSelectTransferMethod_verifyTransferMethodsListUpdatedOnSelection onView(withId(R.id.select_transfer_method_country_value)).check(matches(withText("United States"))); onView(withId(R.id.select_transfer_method_currency_value)).check(matches(withText("USD"))); - onView(withId(R.id.select_transfer_method_types_list)).check(new RecyclerViewCountAssertion(2)); + onView(withId(R.id.select_transfer_method_types_list)).check(new RecyclerViewCountAssertion(4)); onView(withId(R.id.select_transfer_method_country_value)).perform(click()); onView(allOf(withId(R.id.country_name), withText("Canada"))).perform(click()); - onView(withId(R.id.select_transfer_method_types_list)).check(new RecyclerViewCountAssertion(1)); + onView(withId(R.id.select_transfer_method_types_list)).check(new RecyclerViewCountAssertion(2)); onView(withId(R.id.select_transfer_method_types_list)).check( matches(atPosition(0, hasDescendant(withText(R.string.bank_account_font_icon))))); onView(withId(R.id.select_transfer_method_types_list)).check( matches(atPosition(0, hasDescendant(withText(R.string.bank_account))))); onView(withId(R.id.select_transfer_method_types_list)).check( - matches(atPosition(0, hasDescendant(withText("Transaction Fee: USD 2.00"))))); + matches(atPosition(0, hasDescendant(withText("Transaction Fee: CAD 2.20"))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(0, hasDescendant(withText("Processing Time: 1-2 Business days"))))); + + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(1, hasDescendant(withText(R.string.paypal_account_font_icon))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(1, hasDescendant(withText(R.string.paypal_account))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(1, hasDescendant(withText("Transaction Fee: CAD 0.25"))))); onView(withId(R.id.select_transfer_method_types_list)).check( - matches(atPosition(0, hasDescendant(withText("Processing Time: 1-3 Business days"))))); + matches(atPosition(1, hasDescendant(withText("Processing Time: IMMEDIATE"))))); } @@ -307,7 +339,7 @@ public void testSelectTransferMethod_verifyIntentIndividualUser() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_bank_account_response.json")).mock(); mIntentsTestRule.launchActivity(null); @@ -326,7 +358,7 @@ public void testSelectTransferMethod_verifyIntentBusinessUser() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_bank_account_response.json")).mock(); mIntentsTestRule.launchActivity(null); @@ -345,7 +377,7 @@ public void testSelectTransferMethod_clickBankAccountOpensAddTransferMethodUi() mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_bank_account_response.json")).mock(); mActivityTestRule.launchActivity(null); @@ -362,7 +394,7 @@ public void testSelectTransferMethod_clickBankCardOpensAddTransferMethodUi() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("successful_tmc_keys_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("successful_tmc_bank_card_fields_response.json")).mock(); + .getResourceContent("successful_tmc_fields_bank_card_response.json")).mock(); mActivityTestRule.launchActivity(null); diff --git a/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java b/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java index e7ccb6747..28fb0b590 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java @@ -4,6 +4,7 @@ import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.view.View; +import android.widget.EditText; import android.widget.ImageView; import androidx.annotation.NonNull; @@ -131,6 +132,25 @@ public void describeTo(Description description) { }; } + public static Matcher hasEmptyText() { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof EditText)) { + return false; + } + String text = ((EditText) view).getText().toString(); + + return text.isEmpty(); + } + + @Override + public void describeTo(Description description) { + } + }; + } + public static ViewAction nestedScrollTo() { return ViewActions.actionWithAssertions(new NestedScrollToAction()); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java index bea52cb18..a937b371e 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java @@ -24,15 +24,14 @@ * USE OR OTHER DEALINGS * IN THE SOFTWARE. */ - package com.hyperwallet.android.ui.repository; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.hyperwallet.android.model.HyperwalletErrors; -import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationFieldResult; -import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationKeyResult; +import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationField; +import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationKey; public interface TransferMethodConfigurationRepository { @@ -47,15 +46,16 @@ void getFields(@NonNull final String country, @NonNull final String currency, void refreshFields(); interface LoadKeysCallback { - void onKeysLoaded( - @Nullable final HyperwalletTransferMethodConfigurationKeyResult transferMethodConfigurationKeyResult); + + void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKey transferMethodConfigurationKey); void onError(@NonNull final HyperwalletErrors errors); } interface LoadFieldsCallback { - void onFieldsLoaded(@Nullable final HyperwalletTransferMethodConfigurationFieldResult - transferMethodConfigurationFieldResult); + + void onFieldsLoaded(@Nullable final HyperwalletTransferMethodConfigurationField field, + @Nullable final String processingTime); void onError(@NonNull final HyperwalletErrors errors); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java index 89aa23f59..67f2c2278 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java @@ -24,7 +24,6 @@ * USE OR OTHER DEALINGS * IN THE SOFTWARE. */ - package com.hyperwallet.android.ui.repository; import android.os.Handler; @@ -36,8 +35,9 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.exception.HyperwalletException; import com.hyperwallet.android.listener.HyperwalletListener; -import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationFieldResult; -import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationKeyResult; +import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationField; +import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationKey; +import com.hyperwallet.android.model.meta.keyed.HyperwalletTransferMethodType; import com.hyperwallet.android.model.meta.query.HyperwalletTransferMethodConfigurationFieldQuery; import com.hyperwallet.android.model.meta.query.HyperwalletTransferMethodConfigurationKeysQuery; import com.hyperwallet.android.ui.util.EspressoIdlingResource; @@ -45,11 +45,12 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Set; public class TransferMethodConfigurationRepositoryImpl implements TransferMethodConfigurationRepository { - private HyperwalletTransferMethodConfigurationKeyResult mTransferMethodConfigurationKeyResult; + private HyperwalletTransferMethodConfigurationKey mTransferMethodConfigurationKey; private final Handler mHandler; - private final Map mFieldMap; + private final Map mFieldMap; TransferMethodConfigurationRepositoryImpl() { mHandler = new Handler(); @@ -63,11 +64,10 @@ Hyperwallet getHyperwallet() { @VisibleForTesting() protected TransferMethodConfigurationRepositoryImpl(@Nullable Handler handler, - HyperwalletTransferMethodConfigurationKeyResult - transferMethodConfigurationKeyResult, Map fieldMap) { + HyperwalletTransferMethodConfigurationKey transferMethodConfigurationKey, + Map fieldMap) { mHandler = handler; - mTransferMethodConfigurationKeyResult = transferMethodConfigurationKeyResult; + mTransferMethodConfigurationKey = transferMethodConfigurationKey; mFieldMap = fieldMap; } @@ -77,11 +77,11 @@ void getTransferMethodConfigurationKeyResult(final LoadKeysCallback loadKeysCall EspressoIdlingResource.increment(); getHyperwallet().retrieveTransferMethodConfigurationKeys(query, - new HyperwalletListener() { + new HyperwalletListener() { @Override - public void onSuccess(@Nullable HyperwalletTransferMethodConfigurationKeyResult result) { - mTransferMethodConfigurationKeyResult = result; - loadKeysCallback.onKeysLoaded(mTransferMethodConfigurationKeyResult); + public void onSuccess(@Nullable HyperwalletTransferMethodConfigurationKey result) { + mTransferMethodConfigurationKey = result; + loadKeysCallback.onKeysLoaded(mTransferMethodConfigurationKey); EspressoIdlingResource.decrement(); } @@ -106,18 +106,19 @@ void getTransferMethodConfigurationFieldResult(@NonNull final String country, @NonNull final String transferMethodProfileType, @NonNull final LoadFieldsCallback loadFieldsCallback) { HyperwalletTransferMethodConfigurationFieldQuery query = - new HyperwalletTransferMethodConfigurationFieldQuery(country, currency, transferMethodType, - transferMethodProfileType); + new HyperwalletTransferMethodConfigurationFieldQuery(country, currency, + transferMethodType, transferMethodProfileType); EspressoIdlingResource.increment(); getHyperwallet().retrieveTransferMethodConfigurationFields( query, - new HyperwalletListener() { + new HyperwalletListener() { @Override - public void onSuccess(HyperwalletTransferMethodConfigurationFieldResult result) { + public void onSuccess(HyperwalletTransferMethodConfigurationField result) { FieldMapKey fieldMapKey = new FieldMapKey(country, currency, transferMethodType); mFieldMap.put(fieldMapKey, result); - loadFieldsCallback.onFieldsLoaded(result); + loadFieldsCallback.onFieldsLoaded(result, + getProcessingTime(country, currency, transferMethodType)); EspressoIdlingResource.decrement(); } @@ -137,10 +138,10 @@ public Handler getHandler() { @Override public synchronized void getKeys(@NonNull final LoadKeysCallback loadKeysCallback) { - if (mTransferMethodConfigurationKeyResult == null) { + if (mTransferMethodConfigurationKey == null) { getTransferMethodConfigurationKeyResult(loadKeysCallback); } else { - loadKeysCallback.onKeysLoaded(mTransferMethodConfigurationKeyResult); + loadKeysCallback.onKeysLoaded(mTransferMethodConfigurationKey); } } @@ -149,27 +150,45 @@ public synchronized void getFields(@NonNull final String country, @NonNull final @NonNull final String transferMethodType, @NonNull final String transferMethodProfileType, @NonNull final LoadFieldsCallback loadFieldsCallback) { + FieldMapKey fieldMapKey = new FieldMapKey(country, currency, transferMethodType); - HyperwalletTransferMethodConfigurationFieldResult transferMethodConfigurationFieldResult = mFieldMap.get( - fieldMapKey); + 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 (transferMethodConfigurationFieldResult == null) { - getTransferMethodConfigurationFieldResult(country, currency, transferMethodType, transferMethodProfileType, loadFieldsCallback); + if (transferMethodConfigurationField == null) { + getTransferMethodConfigurationFieldResult(country, currency, transferMethodType, + transferMethodProfileType, loadFieldsCallback); } else { - loadFieldsCallback.onFieldsLoaded(transferMethodConfigurationFieldResult); + loadFieldsCallback.onFieldsLoaded(transferMethodConfigurationField, + getProcessingTime(country, currency, transferMethodType)); } } @Override public void refreshKeys() { - mTransferMethodConfigurationKeyResult = null; + mTransferMethodConfigurationKey = null; } @Override public void refreshFields() { mFieldMap.clear(); } + + //TODO this method is just temporary, placed to get the processing time + //Next iteration from API will have ProcessingTime as a separate node + @Nullable + private String getProcessingTime(String country, String currency, String transferMethodType) { + if (mTransferMethodConfigurationKey != null) { + Set transferMethodTypes = mTransferMethodConfigurationKey + .getTransferMethodType(country, currency); + for (HyperwalletTransferMethodType type : transferMethodTypes) { + if (type.getName().equals(transferMethodType)) { + return type.getProcessingTime(); + } + } + } + return null; + } } class FieldMapKey { @@ -213,6 +232,4 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(mCountry, mCurrency, mTransferMethodType); } - - } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepository.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepository.java index 46d5ec781..de222ff69 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepository.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepository.java @@ -39,11 +39,11 @@ void createTransferMethod(@NonNull HyperwalletTransferMethod transferMethod, @NonNull LoadTransferMethodCallback callback); /** - * Load transfe methods available associated with current context + * Load transfer methods available associated with current context * * @param callback @see {@link LoadTransferMethodListCallback} */ - void loadTransferMethod(@NonNull LoadTransferMethodListCallback callback); + void loadTransferMethods(@NonNull LoadTransferMethodListCallback callback); /** * Deactivate transfer method specified. diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java index 7bc72f0c9..4becad682 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java @@ -65,7 +65,7 @@ public void createTransferMethod(@NonNull final HyperwalletTransferMethod transf } @Override - public void loadTransferMethod(@NonNull final LoadTransferMethodListCallback callback) { + public void loadTransferMethods(@NonNull final LoadTransferMethodListCallback callback) { getHyperwallet().listTransferMethods(null, new HyperwalletListener>() { @Override diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java index 93f3aa9da..eb3e29810 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java @@ -20,8 +20,8 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletTransferMethod; -import com.hyperwallet.android.model.meta.Fee; -import com.hyperwallet.android.model.meta.HyperwalletField; +import com.hyperwallet.android.model.meta.HyperwalletFee; +import com.hyperwallet.android.model.meta.field.HyperwalletFieldGroup; import java.util.List; @@ -38,9 +38,9 @@ interface View { void showErrorLoadTransferMethodConfigurationFields(@NonNull final List errors); - void showTransferMethodFields(@NonNull final List fields); + void showTransferMethodFields(@NonNull final List fields); - void showTransactionInformation(List fees, String processingTime); + void showTransactionInformation(List fees, String processingTime); void showCreateButtonProgressBar(); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java index 2507c3eed..659e6a205 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java @@ -16,6 +16,7 @@ */ package com.hyperwallet.android.ui.transfermethod; +import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.PROFILE_TYPE; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_CURRENCY; import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TYPE; @@ -50,8 +51,9 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletTransferMethod; import com.hyperwallet.android.model.PayPalAccount; -import com.hyperwallet.android.model.meta.Fee; -import com.hyperwallet.android.model.meta.HyperwalletField; +import com.hyperwallet.android.model.meta.HyperwalletFee; +import com.hyperwallet.android.model.meta.field.HyperwalletField; +import com.hyperwallet.android.model.meta.field.HyperwalletFieldGroup; import com.hyperwallet.android.ui.HyperwalletLocalBroadcast; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.view.WidgetSelectionDialogFragment; @@ -92,7 +94,6 @@ public class AddTransferMethodFragment extends Fragment implements WidgetEventLi private HyperwalletTransferMethod mTransferMethod; private String mTransferMethodProfileType; private HashMap mWidgetInputStateHashMap; - private TextView sectionHeaderTextView; /** * Please do not use this to have instance of AddTransferMethodFragment this is reserved for android framework @@ -176,8 +177,6 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat super.onViewCreated(view, savedInstanceState); mDynamicContainer = view.findViewById(R.id.add_transfer_method_dynamic_container); - sectionHeaderTextView = view.findViewById(R.id.account_information_section_header); - mCreateButtonProgressBar = view.findViewById(R.id.add_transfer_method_create_button_progress_bar); mProgressBar = view.findViewById(R.id.add_transfer_method_progress_bar_layout); @@ -211,6 +210,7 @@ public void onViewStateRestored(@Nullable Bundle savedInstanceState) { mCountry = savedInstanceState.getString(ARGUMENT_TRANSFER_METHOD_COUNTRY); mCurrency = savedInstanceState.getString(ARGUMENT_TRANSFER_METHOD_CURRENCY); mTransferMethodType = savedInstanceState.getString(ARGUMENT_TRANSFER_METHOD_TYPE); + mTransferMethodProfileType = savedInstanceState.getString(ARGUMENT_TRANSFER_METHOD_PROFILE_TYPE); mShowCreateProgressBar = savedInstanceState.getBoolean(ARGUMENT_SHOW_CREATE_PROGRESS_BAR); mTransferMethod = savedInstanceState.getParcelable(ARGUMENT_TRANSFER_METHOD); } else { // same as AddTransferMethodFragment#newInstance @@ -218,12 +218,9 @@ public void onViewStateRestored(@Nullable Bundle savedInstanceState) { mCountry = getArguments().getString(ARGUMENT_TRANSFER_METHOD_COUNTRY); mCurrency = getArguments().getString(ARGUMENT_TRANSFER_METHOD_CURRENCY); mTransferMethodType = getArguments().getString(ARGUMENT_TRANSFER_METHOD_TYPE); + mTransferMethodProfileType = getArguments().getString(ARGUMENT_TRANSFER_METHOD_PROFILE_TYPE); mTransferMethod = getArguments().getParcelable(ARGUMENT_TRANSFER_METHOD); } - - Locale locale = new Locale.Builder().setRegion(mCountry).build(); - sectionHeaderTextView.setText(requireContext().getResources() - .getString(R.string.account_information_section_header, locale.getDisplayName(), mCurrency)); } @Override @@ -244,6 +241,7 @@ public void onSaveInstanceState(@NonNull Bundle outState) { outState.putString(ARGUMENT_TRANSFER_METHOD_COUNTRY, mCountry); outState.putString(ARGUMENT_TRANSFER_METHOD_CURRENCY, mCurrency); outState.putString(ARGUMENT_TRANSFER_METHOD_TYPE, mTransferMethodType); + outState.putString(ARGUMENT_TRANSFER_METHOD_PROFILE_TYPE, mTransferMethodProfileType); outState.putBoolean(ARGUMENT_SHOW_CREATE_PROGRESS_BAR, mShowCreateProgressBar); outState.putParcelable(ARGUMENT_TRANSFER_METHOD, mTransferMethod); super.onSaveInstanceState(outState); @@ -298,26 +296,37 @@ public void notifyTransferMethodAdded(@NonNull final HyperwalletTransferMethod t } @Override - public void showTransferMethodFields(@NonNull final List fields) { + public void showTransferMethodFields(@NonNull final List fields) { mDynamicContainer.removeAllViews(); - int previousView = 0; + try { - for (final HyperwalletField field : fields) { - AbstractWidget widget = WidgetFactory - .newWidget(field, this, getContext(), - mWidgetInputStateHashMap.containsKey(field.getName()) ? - mWidgetInputStateHashMap.get(field.getName()).getValue() : "", - mCreateTransferMethodButton); - if (mWidgetInputStateHashMap.isEmpty() || !mWidgetInputStateHashMap.containsKey(widget.getName())) { - mWidgetInputStateHashMap.put(widget.getName(), widget.getWidgetInputState()); - } + Locale locale = new Locale.Builder().setRegion(mCountry).build(); + // group + for (HyperwalletFieldGroup 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 HyperwalletField field : group.getFields()) { + AbstractWidget widget = WidgetFactory + .newWidget(field, this, mWidgetInputStateHashMap.containsKey(field.getName()) ? + mWidgetInputStateHashMap.get(field.getName()).getValue() : "", + mCreateTransferMethodButton); + if (mWidgetInputStateHashMap.isEmpty() || !mWidgetInputStateHashMap.containsKey(widget.getName())) { + mWidgetInputStateHashMap.put(widget.getName(), widget.getWidgetInputState()); + } - View widgetView = widget.getView(); - widgetView.setTag(widget); - previousView = placeBelow(widgetView, previousView, true); - final String error = mWidgetInputStateHashMap.get(widget.getName()).getErrorMessage(); - widget.showValidationError(error); - mDynamicContainer.addView(widgetView); + 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); + } } if (mShowCreateProgressBar) { @@ -328,8 +337,20 @@ public void showTransferMethodFields(@NonNull final List field } } + private String getSectionHeaderText(@NonNull final HyperwalletFieldGroup group, @NonNull final Locale locale) { + if (group.getGroupName().equals(HyperwalletFieldGroup.GroupTypes.ACCOUNT_INFORMATION)) { + return requireContext().getResources() + .getString(R.string.account_information_section_header, locale.getDisplayName(), mCurrency); + } + + return requireContext().getString(requireContext().getResources() + .getIdentifier(group.getGroupName().toLowerCase(Locale.ROOT), "string", + requireContext().getPackageName())); + } + @Override - public void showTransactionInformation(@NonNull final List fees, @Nullable final String processingTime) { + public void showTransactionInformation(@NonNull final List fees, + @Nullable final String processingTime) { View header = getView().findViewById(R.id.add_transfer_method_static_container_header); View container = getView().findViewById(R.id.add_transfer_method_static_container); View feeLabel = getView().findViewById(R.id.add_transfer_method_fee_label); @@ -339,7 +360,7 @@ public void showTransactionInformation(@NonNull final List fees, @Nullable int defaultMargin = (int) requireContext().getResources().getDimension(R.dimen.default_margin); - if (!fees.isEmpty()) { + if (fees != null && !fees.isEmpty()) { String formattedFee = FeeFormatter.getFormattedFee(requireContext(), fees); feeValue.setText(formattedFee); feeLabel.setVisibility(View.VISIBLE); @@ -420,7 +441,7 @@ public void showInputErrors(List errors) { AbstractWidget widget = (AbstractWidget) view.getTag(); if (widget.getName().equals(error.getFieldName())) { if (!focusSet) { - widget.getView().requestFocus(); + widget.getView(mDynamicContainer).requestFocus(); focusSet = true; } widget.showValidationError(error.getMessage()); @@ -497,6 +518,8 @@ private void triggerSubmit() { mTransferMethod.setField(widget.getName(), widget.getValue()); } } + + mTransferMethod.setField(PROFILE_TYPE, mTransferMethodProfileType); mPresenter.createTransferMethod(mTransferMethod); } } @@ -524,25 +547,6 @@ private void setVisibleAndDisableFields() { mCreateTransferMethodButton.setBackgroundColor(getResources().getColor(R.color.colorSecondaryDark)); } - private int placeBelow(View v, int previousId, boolean matchParentWidth) { - RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( - matchParentWidth ? ViewGroup.LayoutParams.MATCH_PARENT : ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - - if (previousId != 0) { - params.addRule(RelativeLayout.BELOW, previousId); - } - - int margin = (int) (getContext().getResources().getDimension(R.dimen.default_margin) - / getContext().getResources().getDisplayMetrics().density); - - params.setMargins(margin, margin, margin, margin); - v.setId(View.generateViewId()); - v.setLayoutParams(params); - - return v.getId(); - } - private boolean performValidation(boolean bypassFocusCheck) { boolean valid = true; // this is added since some phones triggers the create button but the widgets are not yet initialized @@ -569,16 +573,7 @@ private boolean performValidation(boolean bypassFocusCheck) { } } } - return valid && hasWidget && haveAllWidgetsReceivedFocus(); - } - - private boolean haveAllWidgetsReceivedFocus() { - for (String key : mWidgetInputStateHashMap.keySet()) { - if (!mWidgetInputStateHashMap.get(key).hasFocused()) { - return false; - } - } - return true; + return valid && hasWidget; } @Override diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java index 73b10717d..8373668bd 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java @@ -17,16 +17,14 @@ package com.hyperwallet.android.ui.transfermethod; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.HyperwalletTransferMethod; -import com.hyperwallet.android.model.meta.Fee; -import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationFieldResult; +import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationField; import com.hyperwallet.android.ui.repository.TransferMethodConfigurationRepository; import com.hyperwallet.android.ui.repository.TransferMethodRepository; -import java.util.List; - public class AddTransferMethodPresenter implements AddTransferMethodContract.Presenter { private static final String TAG = AddTransferMethodContract.class.getName(); @@ -87,21 +85,16 @@ public void loadTransferMethodConfigurationFields(final boolean forceUpdate, @No country, currency, transferMethodType, transferMethodProfileType, new TransferMethodConfigurationRepository.LoadFieldsCallback() { @Override - public void onFieldsLoaded( - HyperwalletTransferMethodConfigurationFieldResult transferMethodConfigurationFieldResult) { + public void onFieldsLoaded(HyperwalletTransferMethodConfigurationField field, + @Nullable final String processingTime) { if (!mView.isActive()) { return; } mView.hideProgressBar(); - mView.showTransferMethodFields(transferMethodConfigurationFieldResult.getFields()); + mView.showTransferMethodFields(field.getFields().getFieldGroups()); // there can be multiple fees when we have flat fee + percentage fees - List fees = transferMethodConfigurationFieldResult - .getFees(country, currency, transferMethodType, transferMethodProfileType); - mView.showTransactionInformation(fees, - transferMethodConfigurationFieldResult - .getProcessingTime(country, currency, transferMethodType, - transferMethodProfileType)); + mView.showTransactionInformation(field.getFees(), processingTime); } @Override diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java index 95cf1cf22..095c218c7 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java @@ -23,13 +23,13 @@ import androidx.annotation.NonNull; import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.model.meta.Fee; +import com.hyperwallet.android.model.meta.HyperwalletFee; import java.util.List; public class FeeFormatter { - public static String getFormattedFee(@NonNull final Context context, @NonNull final List fees) { + public static String getFormattedFee(@NonNull final Context context, @NonNull final List fees) { String formattedString = context.getResources().getString(R.string.unknown); if (fees.size() == 1) { formattedString = getSingleFormattedFee(context, fees, formattedString); @@ -39,13 +39,13 @@ public static String getFormattedFee(@NonNull final Context context, @NonNull fi return formattedString; } - private static String getSingleFormattedFee(@NonNull Context context, @NonNull List fees, + private static String getSingleFormattedFee(@NonNull Context context, @NonNull List fees, String formattedString) { - Fee fee = fees.get(0); - if (Fee.FeeRate.FLAT.equals(fee.getFeeRateType())) { + HyperwalletFee fee = fees.get(0); + if (HyperwalletFee.FeeRate.FLAT.equals(fee.getFeeRateType())) { formattedString = context.getResources().getString(R.string.fee_flat_formatter, fee.getCurrency(), fee.getValue()); - } else if (Fee.FeeRate.PERCENT.equals(fee.getFeeRateType())) { + } else if (HyperwalletFee.FeeRate.PERCENT.equals(fee.getFeeRateType())) { formattedString = getPercentFormattedFee(context, fee); } return formattedString; @@ -53,20 +53,20 @@ private static String getSingleFormattedFee(@NonNull Context context, @NonNull L // we expect at the most 2 fees and in that case one should be flat and other percent // which will be formatted to USD 3.00 + 3% (Min: USD 1.00, Max: USD 15.00) - private static String getMixFormattedFee(@NonNull Context context, @NonNull List fees, + private static String getMixFormattedFee(@NonNull Context context, @NonNull List fees, String formattedString) { - Fee flatFee = null; - Fee percentFee = null; - for (Fee fee : fees) { - if (Fee.FeeRate.FLAT.equals(fee.getFeeRateType())) { + HyperwalletFee flatFee = null; + HyperwalletFee percentFee = null; + for (HyperwalletFee fee : fees) { + if (HyperwalletFee.FeeRate.FLAT.equals(fee.getFeeRateType())) { flatFee = fee; - } else if (Fee.FeeRate.PERCENT.equals(fee.getFeeRateType())) { + } else if (HyperwalletFee.FeeRate.PERCENT.equals(fee.getFeeRateType())) { percentFee = fee; } } if (flatFee != null && percentFee != null) { - String minimumAmount = percentFee.getMinimum(); - String maximumAmount = percentFee.getMaximum(); + String minimumAmount = percentFee.getMin(); + String maximumAmount = percentFee.getMax(); if (maximumAmount.isEmpty() && minimumAmount.isEmpty()) { formattedString = context.getResources().getString(R.string.fee_mix_no_min_and_max_formatter, flatFee.getCurrency(), flatFee.getValue(), percentFee.getValue()); @@ -85,10 +85,10 @@ private static String getMixFormattedFee(@NonNull Context context, @NonNull List } - private static String getPercentFormattedFee(@NonNull final Context context, @NonNull final Fee fee) { + private static String getPercentFormattedFee(@NonNull final Context context, @NonNull final HyperwalletFee fee) { String formattedFee; - String minimumAmount = fee.getMinimum(); - String maximumAmount = fee.getMaximum(); + String minimumAmount = fee.getMin(); + String maximumAmount = fee.getMax(); if (maximumAmount.isEmpty() && minimumAmount.isEmpty()) { formattedFee = context.getResources().getString(R.string.fee_percent_no_min_and_max_formatter, fee.getValue()); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodPresenter.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodPresenter.java index ece9b89d9..5480e0a2e 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodPresenter.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodPresenter.java @@ -38,7 +38,7 @@ public ListTransferMethodPresenter(TransferMethodRepository repository, ListTran @Override public void loadTransferMethods() { mView.showProgressBar(); - mTransferMethodRepository.loadTransferMethod(new TransferMethodRepository.LoadTransferMethodListCallback() { + mTransferMethodRepository.loadTransferMethods(new TransferMethodRepository.LoadTransferMethodListCallback() { @Override public void onTransferMethodListLoaded(List transferMethods) { if (!mView.isActive()) { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java index db873d8f7..193aefd14 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java @@ -19,7 +19,6 @@ package com.hyperwallet.android.ui.transfermethod; import static com.hyperwallet.android.ui.transfermethod.TransferMethodUtils.getStringFontIcon; -import static com.hyperwallet.android.ui.transfermethod.TransferMethodUtils.getStringResourceByName; import android.annotation.SuppressLint; import android.content.Context; @@ -457,8 +456,7 @@ class ViewHolder extends RecyclerView.ViewHolder { @SuppressLint("StringFormatInvalid") void bind(TransferMethodSelectionItem selectionItem) { - mTitle.setText( - getStringResourceByName(mTitle.getContext(), selectionItem.getTransferMethodType())); + mTitle.setText(selectionItem.getTransferMethodName()); mIcon.setText( getStringFontIcon(mIcon.getContext(), selectionItem.getTransferMethodType())); @@ -466,6 +464,7 @@ void bind(TransferMethodSelectionItem selectionItem) { String formattedFee = FeeFormatter.getFormattedFee(mTitle.getContext(), selectionItem.getFees()); mDescriptionFees.setText(mDescriptionFees.getContext() .getString(R.string.select_transfer_method_item_fee_information, formattedFee)); + mDescriptionFees.setVisibility(View.VISIBLE); } else { mDescriptionFees.setVisibility(View.GONE); } @@ -474,6 +473,7 @@ void bind(TransferMethodSelectionItem selectionItem) { mDescriptionProcessingTime.setText(mDescriptionProcessingTime.getContext() .getString(R.string.select_transfer_method_item_processing_time_information, selectionItem.getProcessingTime())); + mDescriptionProcessingTime.setVisibility(View.VISIBLE); } else { mDescriptionProcessingTime.setVisibility(View.INVISIBLE); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java index 4524e8ff0..e5e49cb59 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java @@ -15,7 +15,6 @@ * 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; import androidx.annotation.NonNull; @@ -23,15 +22,17 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.HyperwalletUser; -import com.hyperwallet.android.model.meta.Fee; -import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationKeyResult; +import com.hyperwallet.android.model.meta.HyperwalletTransferMethodConfigurationKey; +import com.hyperwallet.android.model.meta.keyed.Country; +import com.hyperwallet.android.model.meta.keyed.Currency; +import com.hyperwallet.android.model.meta.keyed.HyperwalletTransferMethodType; import com.hyperwallet.android.ui.repository.TransferMethodConfigurationRepository; import com.hyperwallet.android.ui.repository.UserRepository; import java.util.ArrayList; -import java.util.Currency; +import java.util.HashSet; import java.util.List; -import java.util.Locale; +import java.util.Set; import java.util.TreeMap; public class SelectTransferMethodPresenter implements SelectTransferMethodContract.Presenter { @@ -64,20 +65,21 @@ public void onUserLoaded(@NonNull final HyperwalletUser user) { mTransferMethodConfigurationRepository.getKeys( new TransferMethodConfigurationRepository.LoadKeysCallback() { @Override - public void onKeysLoaded( - @Nullable final HyperwalletTransferMethodConfigurationKeyResult transferMethodConfigurationKeyResult) { + public void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKey key) { if (!mView.isActive()) { return; } mView.hideProgressBar(); - List transferMethodTypes = - transferMethodConfigurationKeyResult.getTransferMethods(countryCode, - currencyCode, user.getProfileType()); + Set transferMethodTypes = + key.getTransferMethodType(countryCode, currencyCode) != null + ? key.getTransferMethodType(countryCode, currencyCode) : + new HashSet(); mView.showTransferMethodCountry(countryCode); mView.showTransferMethodCurrency(currencyCode); - mView.showTransferMethodTypes(getTransferMethodSelectionItems(countryCode, currencyCode, - user.getProfileType(), transferMethodTypes, transferMethodConfigurationKeyResult)); + mView.showTransferMethodTypes( + getTransferMethodSelectionItems(countryCode, currencyCode, + user.getProfileType(), transferMethodTypes)); } @Override @@ -110,24 +112,28 @@ public void loadCurrency(final boolean forceUpdate, @NonNull final String countr } mUserRepository.loadUser(new UserRepository.LoadUserCallback() { - @Override public void onUserLoaded(@NonNull final HyperwalletUser user) { mTransferMethodConfigurationRepository.getKeys( new TransferMethodConfigurationRepository.LoadKeysCallback() { @Override - public void onKeysLoaded( - @Nullable final HyperwalletTransferMethodConfigurationKeyResult result) { + public void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKey key) { if (!mView.isActive()) { return; } - List transferMethodCurrencies = result.getCurrencies(countryCode); - List transferMethodTypes = result.getTransferMethods( - countryCode, transferMethodCurrencies.get(0), user.getProfileType()); + List currencies = key.getCurrencies(countryCode) != null ? + new ArrayList<>(key.getCurrencies(countryCode)) : + new ArrayList(); + String currencyCode = currencies.get(0).getCode(); + Set transferMethodTypes = + key.getTransferMethodType(countryCode, currencyCode) != null ? + key.getTransferMethodType(countryCode, currencyCode) : + new HashSet(); mView.showTransferMethodCountry(countryCode); - mView.showTransferMethodCurrency(transferMethodCurrencies.get(0)); + mView.showTransferMethodCurrency(currencies.get(0).getCode()); mView.showTransferMethodTypes(getTransferMethodSelectionItems(countryCode, - transferMethodCurrencies.get(0), user.getProfileType(), transferMethodTypes, result)); + currencies.get(0).getCode(), + user.getProfileType(), transferMethodTypes)); } @Override @@ -142,7 +148,6 @@ public void onError(@NonNull HyperwalletErrors errors) { showErrorLoadCurrency(errors); } }); - } private void showErrorLoadCurrency(@NonNull HyperwalletErrors errors) { @@ -165,20 +170,20 @@ public void onUserLoaded(@NonNull final HyperwalletUser user) { mTransferMethodConfigurationRepository.getKeys( new TransferMethodConfigurationRepository.LoadKeysCallback() { @Override - public void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKeyResult - transferMethodConfigurationKeyResult) { + public void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKey key) { if (!mView.isActive()) { return; } - List transferMethodTypes = - transferMethodConfigurationKeyResult.getTransferMethods( - countryCode, currencyCode, user.getProfileType()); - + Set transferMethodTypes = + key.getTransferMethodType(countryCode, currencyCode) != null ? + key.getTransferMethodType(countryCode, currencyCode) : + new HashSet(); mView.showTransferMethodCountry(countryCode); mView.showTransferMethodCurrency(currencyCode); - mView.showTransferMethodTypes(getTransferMethodSelectionItems(countryCode, currencyCode, - user.getProfileType(), transferMethodTypes, transferMethodConfigurationKeyResult)); + mView.showTransferMethodTypes( + getTransferMethodSelectionItems(countryCode, currencyCode, + user.getProfileType(), transferMethodTypes)); } @Override @@ -199,7 +204,6 @@ public void onError(@NonNull HyperwalletErrors errors) { mView.showErrorLoadTransferMethodTypes(errors.getErrors()); } }); - } @Override @@ -212,21 +216,21 @@ public void openAddTransferMethod(@NonNull final String country, @NonNull final public void loadCountrySelection(@NonNull final String countryCode) { mTransferMethodConfigurationRepository.getKeys(new TransferMethodConfigurationRepository.LoadKeysCallback() { @Override - public void onKeysLoaded( - @Nullable final HyperwalletTransferMethodConfigurationKeyResult transferMethodConfigurationKeyResult) { + public void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationKey key) { if (!mView.isActive()) { return; } - List countryCodes = transferMethodConfigurationKeyResult.getCountries(); + Set countries = key.getCountries(); TreeMap countryNameCodeMap = new TreeMap<>(); - Locale.Builder builder = new Locale.Builder(); - for (String countryCode : countryCodes) { - Locale locale = builder.setRegion(countryCode).build(); - countryNameCodeMap.put(locale.getDisplayName(), countryCode); + String selectedCountryName = ""; + for (Country country : countries) { + if (country.getCode().equals(countryCode)) { + selectedCountryName = country.getName(); + } + countryNameCodeMap.put(country.getName(), country.getCode()); } - Locale locale = new Locale.Builder().setRegion(countryCode).build(); - mView.showCountrySelectionDialog(countryNameCodeMap, locale.getDisplayName()); + mView.showCountrySelectionDialog(countryNameCodeMap, selectedCountryName); } @Override @@ -242,20 +246,23 @@ public void onError(@NonNull final HyperwalletErrors errors) { public void loadCurrencySelection(@NonNull final String countryCode, @NonNull final String currencyCode) { mTransferMethodConfigurationRepository.getKeys(new TransferMethodConfigurationRepository.LoadKeysCallback() { @Override - public void onKeysLoaded( - @Nullable HyperwalletTransferMethodConfigurationKeyResult transferMethodConfigurationKeyResult) { + public void onKeysLoaded(@Nullable HyperwalletTransferMethodConfigurationKey key) { if (!mView.isActive()) { return; } - List currencyCodes = transferMethodConfigurationKeyResult.getCurrencies(countryCode); + Set currencyCodes = key.getCurrencies(countryCode) != null ? + key.getCurrencies(countryCode) : new HashSet(); + TreeMap currencyNameCodeMap = new TreeMap<>(); - for (String currencyCode : currencyCodes) { - Currency currency = Currency.getInstance(currencyCode); - currencyNameCodeMap.put(currency.getDisplayName(), currencyCode); + String selectedCurrencyName = ""; + for (Currency currency : currencyCodes) { + if (currency.getCode().equals(currencyCode)) { + selectedCurrencyName = currency.getName(); + } + currencyNameCodeMap.put(currency.getName(), currency.getCode()); } - mView.showCurrencySelectionDialog(currencyNameCodeMap, - Currency.getInstance(currencyCode).getDisplayName()); + mView.showCurrencySelectionDialog(currencyNameCodeMap, selectedCurrencyName); } @Override @@ -269,20 +276,17 @@ public void onError(@NonNull final HyperwalletErrors errors) { } private List getTransferMethodSelectionItems( - @NonNull final String country, @NonNull final String currency, + @NonNull final String countryCode, @NonNull final String currencyCode, @NonNull final String userProfileType, - @NonNull final List transferMethodTypes, - @NonNull final HyperwalletTransferMethodConfigurationKeyResult result) { + @NonNull final Set transferMethodTypes) { List selectionItems = new ArrayList<>(); - for (String transferMethodType : transferMethodTypes) { - List fees = result.getFees(country, currency, transferMethodType, userProfileType); - String processingTime = result.getProcessingTime(country, currency, transferMethodType, userProfileType); - TransferMethodSelectionItem data = new TransferMethodSelectionItem(country, currency, userProfileType, - transferMethodType, processingTime, fees); + for (HyperwalletTransferMethodType transferMethodType : transferMethodTypes) { + TransferMethodSelectionItem data = new TransferMethodSelectionItem(countryCode, currencyCode, + userProfileType, transferMethodType.getCode(), transferMethodType.getName(), + transferMethodType.getProcessingTime(), transferMethodType.getFees()); selectionItems.add(data); } return selectionItems; } - } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java index d065d7ac1..c3c7af373 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java @@ -18,29 +18,34 @@ import androidx.annotation.NonNull; -import com.hyperwallet.android.model.meta.Fee; +import com.hyperwallet.android.model.meta.HyperwalletFee; +import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Set; public class TransferMethodSelectionItem { private final String mCountry; private final String mCurrency; - private final List mFees; + private final List mFees; private final String mProcessingTime; private final String mProfileType; private final String mTransferMethodType; + private final String mTransferMethodName; public TransferMethodSelectionItem(@NonNull final String country, @NonNull final String currency, @NonNull final String profileType, @NonNull final String transferMethodType, - @NonNull final String processingTime, @NonNull final List fees) { + @NonNull final String transferMethodName, @NonNull final String processingTime, + @NonNull final Set fees) { mCountry = country; mCurrency = currency; mProfileType = profileType; mTransferMethodType = transferMethodType; + mTransferMethodName = transferMethodName; mProcessingTime = processingTime; - mFees = fees; + mFees = new ArrayList<>(fees); } public String getCountry() { @@ -55,6 +60,10 @@ public String getProfileType() { return mProfileType; } + public String getTransferMethodName() { + return mTransferMethodName; + } + public String getTransferMethodType() { return mTransferMethodType; } @@ -63,7 +72,7 @@ public String getProcessingTime() { return mProcessingTime; } - public List getFees() { + public List getFees() { return mFees; } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java index 7bed35b21..5dab1341b 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java @@ -16,19 +16,27 @@ */ package com.hyperwallet.android.ui.view; +import android.app.SearchManager; import android.content.Context; import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import android.view.inputmethod.EditorInfo; +import android.widget.Filter; +import android.widget.Filterable; import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import androidx.fragment.app.DialogFragment; @@ -41,19 +49,23 @@ import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.TreeMap; public class WidgetSelectionDialogFragment extends DialogFragment implements ToolbarEventListener { public static final String TAG = WidgetSelectionDialogFragment.class.getName(); private static final String ARGUMENT_NAME_VALUE_MAP = "ARGUMENT_NAME_VALUE_MAP"; + private static final String ARGUMENT_SEARCH_SELECTED_NAME_QUERY = "ARGUMENT_SEARCH_SELECTED_NAME_QUERY"; private static final String ARGUMENT_SELECTED_NAME = "ARGUMENT_SELECTED_NAME"; private static final String ARGUMENT_SELECTION_LABEL = "ARGUMENT_SELECTION_LABEL"; private static final String ARGUMENT_SELECTION_FIELD_NAME = "ARGUMENT_SELECTION_FIELD_NAME"; + private static final int MAX_NO_SEARCH_COUNT = 20; private Adapter mAdapter; private String mFieldName; private TreeMap mNameValueMap; + private String mSearchNameQuery; private String mSelectedName; private String mSelectionLabel; private WidgetSelectionItemListener mWidgetSelectionItemListener; @@ -66,12 +78,14 @@ public static WidgetSelectionDialogFragment newInstance(@NonNull final TreeMap MAX_NO_SEARCH_COUNT); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + menu.clear(); + inflater.inflate(R.menu.menu_widget_selection, menu); + + SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); + MenuItem searchItem = menu.findItem(R.id.widget_selection_search_item); + SearchView searchView = (SearchView) searchItem.getActionView(); + searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName())); + searchView.setMaxWidth(Integer.MAX_VALUE); + searchView.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + mSearchNameQuery = query; + mAdapter.getFilter().filter(query); + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + mSearchNameQuery = newText; + mAdapter.getFilter().filter(newText); + return false; + } + }); + + if (!mSearchNameQuery.isEmpty()) { + searchView.clearFocus(); + searchItem.expandActionView(); + searchView.setQuery(mSearchNameQuery, true); } } @@ -181,15 +232,16 @@ public interface WidgetSelectionItemListener { void onWidgetSelectionItemClicked(@NonNull final String selectedValue, @NonNull final String fieldName); } - private static class Adapter extends RecyclerView.Adapter { + private static class Adapter extends RecyclerView.Adapter implements Filterable { + private final Fragment mFragment; + private final String mFieldName; private final TreeMap mNameValueMap; private final String mSelectedName; - private final List mSelectionList; private final ToolbarEventListener mToolbarEventListener; - private final Fragment mFragment; - private final String mFieldName; private final WidgetSelectionItemListener mWidgetSelectionItemListener; + private TreeMap mNameValueFilteredMap; + private List mSelectionList; Adapter(@NonNull final TreeMap nameValueMap, @NonNull final String selectedName, @NonNull final Fragment fragment, @NonNull final ToolbarEventListener toolbarEventListener, @@ -198,6 +250,7 @@ private static class Adapter extends RecyclerView.Adapter { mSelectionList = new ArrayList<>(nameValueMap.keySet()); mSelectedName = selectedName; mNameValueMap = nameValueMap; + mNameValueFilteredMap = nameValueMap; mToolbarEventListener = toolbarEventListener; mFragment = fragment; mFieldName = fieldName; @@ -243,6 +296,37 @@ String getItemValue(int position) { return mNameValueMap.get(mSelectionList.get(position)); } + @Override + public Filter getFilter() { + return new Filter() { + @Override + protected FilterResults performFiltering(CharSequence constraint) { + if (constraint.length() == 0) { + mSelectionList = new ArrayList<>(mNameValueMap.keySet()); + mNameValueFilteredMap = mNameValueMap; + } else { + mNameValueFilteredMap = new TreeMap<>(); + for (String selection : mNameValueMap.keySet()) { + if (selection.toLowerCase(Locale.ROOT) + .contains(constraint.toString().toLowerCase(Locale.ROOT))) { + mNameValueFilteredMap.put(selection, mNameValueMap.get(selection)); + } + } + mSelectionList = new ArrayList<>(mNameValueFilteredMap.keySet()); + } + FilterResults filterResults = new FilterResults(); + filterResults.values = mNameValueFilteredMap; + return filterResults; + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) { + mNameValueFilteredMap = (TreeMap) results.values; + notifyDataSetChanged(); + } + }; + } + class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { final TextView mSelectName; final ImageView mSelectItemImage; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/AbstractWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/AbstractWidget.java index 9ec0cec5d..211e120c6 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/AbstractWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/AbstractWidget.java @@ -16,8 +16,6 @@ */ package com.hyperwallet.android.ui.view.widget; -import android.content.Context; -import android.os.Build; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; @@ -26,14 +24,12 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.model.meta.HyperwalletField; +import com.hyperwallet.android.model.meta.field.HyperwalletField; public abstract class AbstractWidget { private static final String LABEL_SUFFIX = "Label"; - protected final Context mContext; protected final View mDefaultFocusView; protected final String mDefaultValue; protected final HyperwalletField mField; @@ -42,16 +38,15 @@ public abstract class AbstractWidget { protected WidgetInputState mWidgetInputState; public AbstractWidget(@Nullable HyperwalletField field, @NonNull WidgetEventListener listener, - @NonNull Context context, @Nullable String defaultValue, @NonNull View defaultFocusView) { + @Nullable String defaultValue, @NonNull View defaultFocusView) { mField = field; mListener = listener; - mContext = context; mDefaultValue = defaultValue; mDefaultFocusView = defaultFocusView; mWidgetInputState = new WidgetInputState(getName()); } - public abstract View getView(); + public abstract View getView(@NonNull final ViewGroup viewGroup); public String getName() { return mField == null ? "" : mField.getName(); @@ -128,17 +123,6 @@ protected void appendLayout(View v, boolean matchParentWidth) { params.addRule(RelativeLayout.BELOW, mBottomViewId); } - int default_margin = (int) (mContext.getResources().getDimension(R.dimen.default_margin) - / mContext.getResources().getDisplayMetrics().density); - int widget_margin_offset = (int) (mContext.getResources().getDimension(R.dimen.widget_left_margin_offset) - / mContext.getResources().getDisplayMetrics().density); - - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { - params.setMargins(default_margin, default_margin, default_margin, default_margin); - } else { - params.setMargins(widget_margin_offset, default_margin, default_margin, default_margin); - } - v.setLayoutParams(params); mBottomViewId = v.getId(); } @@ -148,7 +132,7 @@ protected void setIdFromFieldName(View view) { if (fieldName.isEmpty()) { view.setId(View.generateViewId()); } else { - view.setId(getIdByResourceName(fieldName)); + view.setId(getIdByResourceName(fieldName, view)); } } @@ -157,17 +141,15 @@ protected void setIdFromFieldLabel(View view) { if (fieldName.isEmpty()) { view.setId(View.generateViewId()); } else { - view.setId(getIdByResourceName(fieldName + LABEL_SUFFIX)); + view.setId(getIdByResourceName(fieldName + LABEL_SUFFIX, view)); } } - private int getIdByResourceName(@NonNull final String fieldName) { - int id; - final int idFromResource = mContext.getResources().getIdentifier(fieldName, "id", - mContext.getPackageName()); - // Returns 0 if no such resource was found. - id = idFromResource == 0 ? View.generateViewId() : idFromResource; - return id; + private int getIdByResourceName(@NonNull final String fieldName, @NonNull final View view) { + final int idFromResource = view.getContext().getResources().getIdentifier(fieldName, "id", + view.getContext().getPackageName()); + + return idFromResource == 0 ? View.generateViewId() : idFromResource; } protected class DefaultKeyListener implements View.OnKeyListener { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java index a3ba9d932..00746d090 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java @@ -16,46 +16,52 @@ */ package com.hyperwallet.android.ui.view.widget; -import android.content.Context; import android.text.Editable; import android.text.InputType; +import android.text.TextUtils; import android.text.TextWatcher; import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.EditText; -import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.model.meta.HyperwalletField; +import com.hyperwallet.android.model.meta.field.HyperwalletField; public class DateWidget extends AbstractWidget { private ViewGroup mContainer; - private String mValue = ""; + private String mValue; private TextInputLayout mTextInputLayout; - public DateWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, @NonNull Context context, + public DateWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, @Nullable String defaultValue, @NonNull View defaultFocusView) { - super(field, listener, context, defaultValue, defaultFocusView); + super(field, listener, defaultValue, defaultFocusView); mValue = defaultValue; } @Override - public View getView() { + public View getView(@NonNull final ViewGroup viewGroup) { if (mContainer == null) { - mContainer = new RelativeLayout(mContext); - mTextInputLayout = new TextInputLayout( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputLayout)); + mContainer = (ViewGroup) LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_widget_layout, viewGroup, false); + // input control + mTextInputLayout = new TextInputLayout(new ContextThemeWrapper(viewGroup.getContext(), + mField.isEditable() ? R.style.Widget_Hyperwallet_TextInputLayout + : R.style.Widget_Hyperwallet_TextInputLayout_Disabled)); final EditText editText = new EditText( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputEditText)); + new ContextThemeWrapper(viewGroup.getContext(), R.style.Widget_Hyperwallet_TextInputEditText)); + + editText.setEnabled(mField.isEditable()); setIdFromFieldName(editText); + setIdFromFieldLabel(mTextInputLayout); mTextInputLayout.setHint(mField.getLabel()); mTextInputLayout.addView(editText); @@ -88,10 +94,10 @@ public void afterTextChanged(Editable s) { } }); + editText.setText(TextUtils.isEmpty(mDefaultValue) ? mField.getValue() : mDefaultValue); editText.setInputType(InputType.TYPE_CLASS_DATETIME); editText.setOnKeyListener(new DefaultKeyListener(mDefaultFocusView, editText)); editText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_NEXT); - editText.setText(mDefaultValue); appendLayout(mTextInputLayout, true); mContainer.addView(mTextInputLayout); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DefaultAccountWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DefaultAccountWidget.java index fc1e66687..9463f308f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DefaultAccountWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DefaultAccountWidget.java @@ -2,7 +2,6 @@ import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.IS_DEFAULT_TRANSFER_METHOD; -import android.content.Context; import android.graphics.Typeface; import android.view.View; import android.view.ViewGroup; @@ -21,9 +20,9 @@ public class DefaultAccountWidget extends AbstractWidget { private ViewGroup mContainer; private String mValue; - public DefaultAccountWidget(@NonNull WidgetEventListener listener, @NonNull Context context, + public DefaultAccountWidget(@NonNull WidgetEventListener listener, @Nullable String defaultValue, @NonNull View defaultFocusView) { - super(null, listener, context, defaultValue, defaultFocusView); + super(null, listener, defaultValue, defaultFocusView); } @Override @@ -32,26 +31,26 @@ public String getName() { } @Override - public View getView() { + public View getView(@NonNull final ViewGroup viewGroup) { if (mContainer == null) { - mContainer = new RelativeLayout(mContext); + mContainer = new RelativeLayout(viewGroup.getContext()); // label - TextView label = new TextView(mContext); - label.setText(mContext.getResources().getText(R.string.default_account_label)); + TextView label = new TextView(viewGroup.getContext()); + label.setText(viewGroup.getContext().getResources().getText(R.string.default_account_label)); - label.setTextSize(mContext.getResources().getDimension(R.dimen.font_subtitle2)); + label.setTextSize(viewGroup.getContext().getResources().getDimension(R.dimen.font_subtitle2)); setIdFromFieldLabel(label); label.setTypeface(null, Typeface.BOLD); - label.setTextColor(mContext.getResources().getColor(R.color.colorPrimary)); + label.setTextColor(viewGroup.getContext().getResources().getColor(R.color.colorPrimary)); appendLayout(label, true); mContainer.addView(label); // switch control - Switch toggle = new Switch(mContext); + Switch toggle = new Switch(viewGroup.getContext()); setIdFromFieldName(toggle); - toggle.setText(mContext.getResources().getText(R.string.default_account_sub_label)); - toggle.setTextSize(mContext.getResources().getDimension(R.dimen.font_subtitle2)); + toggle.setText(viewGroup.getContext().getResources().getText(R.string.default_account_sub_label)); + toggle.setTextSize(viewGroup.getContext().getResources().getDimension(R.dimen.font_subtitle2)); if (mDefaultValue == null) { toggle.setChecked(true); // initial state mValue = Boolean.TRUE.toString(); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java index d6f5b00ed..9777f2153 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java @@ -27,43 +27,55 @@ import android.text.TextUtils; import android.text.TextWatcher; import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; -import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.model.meta.HyperwalletField; +import com.hyperwallet.android.model.meta.field.HyperwalletField; public class ExpiryDateWidget extends AbstractWidget { private ViewGroup mContainer; private final ExpireDateUtil mExpireDateUtil; private TextInputLayout mTextInputLayout; private String mValue; + private String mMessageInvalidDateLength; + private String mMessageInvalidDate; public ExpiryDateWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, - @NonNull Context context, @Nullable String defaultValue, @NonNull View defaultFocusView) { - super(field, listener, context, defaultValue, defaultFocusView); + @Nullable String defaultValue, @NonNull View defaultFocusView) { + super(field, listener, defaultValue, defaultFocusView); mValue = defaultValue; mExpireDateUtil = new ExpireDateUtil(); } @Override - public View getView() { + public View getView(@NonNull final ViewGroup viewGroup) { if (mContainer == null) { - mContainer = new RelativeLayout(mContext); + mContainer = (ViewGroup) LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_widget_layout, viewGroup, false); + + // initialize messaging + mMessageInvalidDateLength = viewGroup.getContext().getResources() + .getString(R.string.error_exact_length_field, MAX_INPUT_LENGTH); + mMessageInvalidDate = viewGroup.getContext().getResources() + .getString(R.string.error_invalid_expiry_date, mField.getLabel()); // input control - mTextInputLayout = new TextInputLayout( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputLayout)); + mTextInputLayout = new TextInputLayout(new ContextThemeWrapper(viewGroup.getContext(), + mField.isEditable() ? R.style.Widget_Hyperwallet_TextInputLayout + : R.style.Widget_Hyperwallet_TextInputLayout_Disabled)); final EditText editText = new EditText( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputEditText)); + new ContextThemeWrapper(viewGroup.getContext(), R.style.Widget_Hyperwallet_TextInputEditText)); + + editText.setEnabled(mField.isEditable()); setIdFromFieldLabel(mTextInputLayout); setIdFromFieldName(editText); editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @@ -75,10 +87,10 @@ public void onFocusChange(View v, boolean hasFocus) { } else { mListener.widgetFocused(ExpiryDateWidget.this.getName()); editText.setHint(editText.getText().toString().trim().isEmpty() ? - mContext.getResources().getString(R.string.api_expiry_date_format) : ""); + viewGroup.getContext().getResources().getString(R.string.api_expiry_date_format) : ""); InputMethodManager imm = (InputMethodManager) - mContext.getSystemService(Context.INPUT_METHOD_SERVICE); + viewGroup.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); } } @@ -170,8 +182,9 @@ public void afterTextChanged(Editable s) { editText.setInputType(InputType.TYPE_CLASS_DATETIME); editText.setHint(mField.getLabel()); - editText.setText(TextUtils.isEmpty(mDefaultValue) ? "" : - mExpireDateUtil.convertDateFromServerFormat(mDefaultValue)); + editText.setText(mExpireDateUtil.convertDateFromServerFormat( + TextUtils.isEmpty(mDefaultValue) ? mField.getValue() : mDefaultValue)); + editText.setOnKeyListener(new DefaultKeyListener(mDefaultFocusView, editText)); editText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_NEXT); @@ -203,11 +216,11 @@ public String getErrorMessage() { } if (isInvalidLength()) { - return mContext.getResources().getString(R.string.error_exact_length_field, MAX_INPUT_LENGTH); + return mMessageInvalidDateLength; } if (mExpireDateUtil.isInvalidDate(mValue)) { - return mContext.getResources().getString(R.string.error_invalid_expiry_date, mField.getLabel()); + return mMessageInvalidDate; } return null; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/NumberWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/NumberWidget.java index cafa5e9c2..39dcc7eed 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/NumberWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/NumberWidget.java @@ -16,45 +16,50 @@ */ package com.hyperwallet.android.ui.view.widget; -import android.content.Context; import android.text.Editable; import android.text.InputType; +import android.text.TextUtils; import android.text.TextWatcher; import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.EditText; -import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.model.meta.HyperwalletField; +import com.hyperwallet.android.model.meta.field.HyperwalletField; public class NumberWidget extends AbstractWidget { private ViewGroup mContainer; private TextInputLayout mTextInputLayout; - private String mValue = ""; + private String mValue; public NumberWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, - @NonNull Context context, @Nullable String defaultValue, @NonNull View defaultFocusView) { - super(field, listener, context, defaultValue, defaultFocusView); + @Nullable String defaultValue, @NonNull View defaultFocusView) { + super(field, listener, defaultValue, defaultFocusView); mValue = defaultValue; } @Override - public View getView() { + public View getView(@NonNull final ViewGroup viewGroup) { if (mContainer == null) { - mContainer = new RelativeLayout(mContext); + mContainer = (ViewGroup) LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_widget_layout, viewGroup, false); + // number input text - mTextInputLayout = new TextInputLayout( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputLayout)); + mTextInputLayout = new TextInputLayout(new ContextThemeWrapper(viewGroup.getContext(), + mField.isEditable() ? R.style.Widget_Hyperwallet_TextInputLayout + : R.style.Widget_Hyperwallet_TextInputLayout_Disabled)); mTextInputLayout.setHint(mField.getLabel()); + final EditText editText = new EditText( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputEditText)); + new ContextThemeWrapper(viewGroup.getContext(), R.style.Widget_Hyperwallet_TextInputEditText)); + editText.setEnabled(mField.isEditable()); setIdFromFieldLabel(mTextInputLayout); setIdFromFieldName(editText); @@ -87,9 +92,9 @@ public void afterTextChanged(Editable s) { } }); + editText.setText(TextUtils.isEmpty(mDefaultValue) ? mField.getValue() : mDefaultValue); editText.setInputType(InputType.TYPE_CLASS_NUMBER); editText.setOnKeyListener(new DefaultKeyListener(mDefaultFocusView, editText)); - editText.setText(mDefaultValue); editText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_NEXT); mTextInputLayout.addView(editText); appendLayout(mTextInputLayout, true); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/PhoneWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/PhoneWidget.java index 7bce341f7..b0d2b8e0f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/PhoneWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/PhoneWidget.java @@ -16,48 +16,54 @@ */ package com.hyperwallet.android.ui.view.widget; -import android.content.Context; import android.text.Editable; import android.text.InputType; +import android.text.TextUtils; import android.text.TextWatcher; import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.EditText; -import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.model.meta.HyperwalletField; +import com.hyperwallet.android.model.meta.field.HyperwalletField; public class PhoneWidget extends AbstractWidget { private ViewGroup mContainer; private String mValue = ""; private TextInputLayout mTextInputLayout; - public PhoneWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, @NonNull Context context, + public PhoneWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, @Nullable String defaultValue, @NonNull View defaultFocusView) { - super(field, listener, context, defaultValue, defaultFocusView); + super(field, listener, defaultValue, defaultFocusView); mValue = defaultValue; } @Override - public View getView() { + public View getView(@NonNull final ViewGroup viewGroup) { if (mContainer == null) { - mContainer = new RelativeLayout(mContext); - mTextInputLayout = new TextInputLayout( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputLayout)); + mContainer = (ViewGroup) LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_widget_layout, viewGroup, false); + + mTextInputLayout = new TextInputLayout(new ContextThemeWrapper(viewGroup.getContext(), + mField.isEditable() ? R.style.Widget_Hyperwallet_TextInputLayout + : R.style.Widget_Hyperwallet_TextInputLayout_Disabled)); + // input control final EditText editText = new EditText( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputEditText)); + new ContextThemeWrapper(viewGroup.getContext(), R.style.Widget_Hyperwallet_TextInputEditText)); + editText.setEnabled(mField.isEditable()); + mTextInputLayout.addView(editText); mTextInputLayout.setHint(mField.getLabel()); setIdFromFieldName(editText); - + setIdFromFieldLabel(mTextInputLayout); editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { @@ -87,10 +93,10 @@ public void afterTextChanged(Editable s) { } }); + editText.setText(TextUtils.isEmpty(mDefaultValue) ? mField.getValue() : mDefaultValue); editText.setInputType(InputType.TYPE_CLASS_PHONE); editText.setOnKeyListener(new DefaultKeyListener(mDefaultFocusView, editText)); editText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_NEXT); - editText.setText(mDefaultValue); appendLayout(mTextInputLayout, true); mContainer.addView(mTextInputLayout); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/SelectionWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/SelectionWidget.java index a9f34045a..146de1b65 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/SelectionWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/SelectionWidget.java @@ -17,15 +17,14 @@ package com.hyperwallet.android.ui.view.widget; import android.app.Activity; -import android.content.Context; import android.text.TextUtils; import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; -import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -33,11 +32,10 @@ import com.google.android.material.textfield.TextInputLayout; import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.model.meta.HyperwalletField; -import com.hyperwallet.android.model.meta.HyperwalletFieldSelectionOption; +import com.hyperwallet.android.model.meta.field.HyperwalletField; +import com.hyperwallet.android.model.meta.field.HyperwalletFieldSelectionOption; import com.hyperwallet.android.ui.view.WidgetSelectionDialogFragment; -import java.util.Locale; import java.util.Set; import java.util.TreeMap; @@ -50,41 +48,43 @@ public class SelectionWidget extends AbstractWidget implements WidgetSelectionDi private String mValue; public SelectionWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, - @NonNull Context context, @Nullable String defaultValue, @NonNull View defaultFocusView) { - super(field, listener, context, defaultValue, defaultFocusView); + @Nullable String defaultValue, @NonNull View defaultFocusView) { + super(field, listener, defaultValue, defaultFocusView); mValue = defaultValue; mSelectionNameValueMap = new TreeMap<>(); - for (HyperwalletFieldSelectionOption option : field.getFieldSelectionOptions()) { - if (!TextUtils.isEmpty(option.getLabel())) { - String label = option.getLabel().substring(1).toLowerCase(Locale.ROOT); - label = option.getLabel().substring(0, 1) + label; - mSelectionNameValueMap.put(label, option.getValue()); + if (field.getFieldSelectionOptions() != null) { + for (HyperwalletFieldSelectionOption option : field.getFieldSelectionOptions()) { + if (!TextUtils.isEmpty(option.getLabel())) { + mSelectionNameValueMap.put(option.getLabel(), option.getValue()); + } } } } @Override - public View getView() { + public View getView(@NonNull final ViewGroup viewGroup) { if (mContainer == null) { - mContainer = new RelativeLayout(mContext); + mContainer = (ViewGroup) LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_widget_layout, viewGroup, false); + setIdFromFieldLabel(mContainer); mContainer.setFocusable(true); mContainer.setFocusableInTouchMode(true); - mTextInputLayout = new TextInputLayout( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputLayout)); + mTextInputLayout = new TextInputLayout(new ContextThemeWrapper(viewGroup.getContext(), + mField.isEditable() ? R.style.Widget_Hyperwallet_TextInputLayout + : R.style.Widget_Hyperwallet_TextInputLayout_Disabled)); mEditText = new EditText( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputEditText)); - if (!TextUtils.isEmpty(mDefaultValue)) { - mEditText.setText(getKeyFromValue(mDefaultValue)); - } + new ContextThemeWrapper(viewGroup.getContext(), R.style.Widget_Hyperwallet_TextInputEditText)); + mEditText.setText( + getKeyFromValue(TextUtils.isEmpty(mDefaultValue) ? mValue = mField.getValue() : mDefaultValue)); setIdFromFieldLabel(mTextInputLayout); setIdFromFieldName(mEditText); mEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); mEditText.setKeyListener(null); mEditText.setCompoundDrawablesWithIntrinsicBounds(null, null, - ContextCompat.getDrawable(mContext, R.drawable.ic_keyboard_arrow_down_12dp), null); + ContextCompat.getDrawable(viewGroup.getContext(), R.drawable.ic_keyboard_arrow_down_12dp), null); mEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override @@ -104,13 +104,17 @@ public void onFocusChange(View v, boolean hasFocus) { } }); - mEditText.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - hideSoftKey(v); - showSelectionFragmentDialog(); - } - }); + if (mField.isEditable()) { + mEditText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + hideSoftKey(v); + showSelectionFragmentDialog(); + } + }); + } else { + mEditText.setEnabled(false); + } mTextInputLayout.setHint(mField.getLabel()); mTextInputLayout.addView(mEditText); @@ -145,7 +149,8 @@ private void hideSoftKey(@NonNull View focusedView) { private void showSelectionFragmentDialog() { String defaultSelected = TextUtils.isEmpty(mValue) ? - TextUtils.isEmpty(mDefaultValue) ? "" : getKeyFromValue(mDefaultValue) : getKeyFromValue(mValue); + TextUtils.isEmpty(mDefaultValue) ? getKeyFromValue(mField.getValue()) : + getKeyFromValue(mDefaultValue) : getKeyFromValue(mValue); mListener.openWidgetSelectionFragmentDialog(mSelectionNameValueMap, defaultSelected, mField.getLabel(), mField.getName()); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/TextWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/TextWidget.java index fb8e322ec..f16fd51c0 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/TextWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/TextWidget.java @@ -16,46 +16,51 @@ */ package com.hyperwallet.android.ui.view.widget; -import android.content.Context; import android.text.Editable; import android.text.InputType; +import android.text.TextUtils; import android.text.TextWatcher; import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.EditText; -import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.model.meta.HyperwalletField; +import com.hyperwallet.android.model.meta.field.HyperwalletField; public class TextWidget extends AbstractWidget { private ViewGroup mContainer; - private String mValue = ""; + private String mValue; private TextInputLayout mTextInputLayout; - public TextWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, @NonNull Context context, + public TextWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, @Nullable String defaultValue, @NonNull View defaultFocusView) { - super(field, listener, context, defaultValue, defaultFocusView); + super(field, listener, defaultValue, defaultFocusView); mValue = defaultValue; } @Override - public View getView() { + public View getView(@NonNull final ViewGroup viewGroup) { if (mContainer == null) { - mContainer = new RelativeLayout(mContext); + mContainer = (ViewGroup) LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_widget_layout, viewGroup, false); mContainer.setTag(mField.getName()); - mTextInputLayout = new TextInputLayout( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputLayout)); + + mTextInputLayout = new TextInputLayout(new ContextThemeWrapper(viewGroup.getContext(), + mField.isEditable() ? R.style.Widget_Hyperwallet_TextInputLayout + : R.style.Widget_Hyperwallet_TextInputLayout_Disabled)); + final EditText editText = new EditText( - new ContextThemeWrapper(mContext, R.style.Widget_Hyperwallet_TextInputEditText)); - mTextInputLayout.setHint(mField.getLabel()); + new ContextThemeWrapper(viewGroup.getContext(), R.style.Widget_Hyperwallet_TextInputEditText)); + editText.setEnabled(mField.isEditable()); + mTextInputLayout.setHint(mField.getLabel()); setIdFromFieldLabel(mTextInputLayout); setIdFromFieldName(editText); editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @@ -87,10 +92,10 @@ public void afterTextChanged(Editable s) { } }); + editText.setText(TextUtils.isEmpty(mDefaultValue) ? mField.getValue() : mDefaultValue); editText.setInputType(InputType.TYPE_CLASS_TEXT); editText.setOnKeyListener(new DefaultKeyListener(mDefaultFocusView, editText)); editText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_NEXT); - editText.setText(mDefaultValue); mTextInputLayout.addView(editText); appendLayout(mTextInputLayout, true); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/WidgetFactory.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/WidgetFactory.java index 405cd2df9..18bd507ca 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/WidgetFactory.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/WidgetFactory.java @@ -16,22 +16,20 @@ */ package com.hyperwallet.android.ui.view.widget; -import android.content.Context; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.hyperwallet.android.exception.HyperwalletException; -import com.hyperwallet.android.model.meta.EDataType; -import com.hyperwallet.android.model.meta.HyperwalletField; +import com.hyperwallet.android.model.meta.field.EDataType; +import com.hyperwallet.android.model.meta.field.HyperwalletField; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; public class WidgetFactory { - private static final String TAG = AbstractWidget.class.getName(); private static final HashMap WIDGET_MAP_DEFINITION = new HashMap() {{ put(EDataType.TEXT, TextWidget.class); put(EDataType.SELECTION, SelectionWidget.class); @@ -43,18 +41,17 @@ public class WidgetFactory { @SuppressWarnings("unchecked") public static AbstractWidget newWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, - @NonNull Context context, @Nullable String defaultValue, @NonNull View view) throws HyperwalletException { + @Nullable String defaultValue, @NonNull View view) throws HyperwalletException { try { if (WIDGET_MAP_DEFINITION.containsKey(field.getDataType())) { return (AbstractWidget) WIDGET_MAP_DEFINITION.get(field.getDataType()) - .getConstructor(HyperwalletField.class, WidgetEventListener.class, - Context.class, String.class, View.class) - .newInstance(field, listener, context, defaultValue, view); + .getConstructor(HyperwalletField.class, WidgetEventListener.class, String.class, View.class) + .newInstance(field, listener, defaultValue, view); } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) { throw new HyperwalletException(e); } - return new TextWidget(field, listener, context, defaultValue, view); + return new TextWidget(field, listener, defaultValue, view); } } diff --git a/ui/src/main/res/layout/fragment_add_transfer_method.xml b/ui/src/main/res/layout/fragment_add_transfer_method.xml index d7d00c13d..861e1bdcd 100644 --- a/ui/src/main/res/layout/fragment_add_transfer_method.xml +++ b/ui/src/main/res/layout/fragment_add_transfer_method.xml @@ -36,21 +36,6 @@ android:layout_height="wrap_content" android:orientation="vertical"> - - - - - + \ No newline at end of file diff --git a/ui/src/main/res/layout/item_widget_section_header.xml b/ui/src/main/res/layout/item_widget_section_header.xml new file mode 100644 index 000000000..10e63e4ab --- /dev/null +++ b/ui/src/main/res/layout/item_widget_section_header.xml @@ -0,0 +1,15 @@ + + + + diff --git a/ui/src/main/res/menu/menu_widget_selection.xml b/ui/src/main/res/menu/menu_widget_selection.xml new file mode 100644 index 000000000..41b5f332e --- /dev/null +++ b/ui/src/main/res/menu/menu_widget_selection.xml @@ -0,0 +1,10 @@ + +

+ + \ No newline at end of file diff --git a/ui/src/main/res/values/dimens.xml b/ui/src/main/res/values/dimens.xml index af96abda6..1a3f3fb32 100644 --- a/ui/src/main/res/values/dimens.xml +++ b/ui/src/main/res/values/dimens.xml @@ -47,6 +47,10 @@ 32dp 330dp + + 8dp + 12dp + 136dp 1dp diff --git a/ui/src/main/res/values/ids.xml b/ui/src/main/res/values/ids.xml index df6202824..1fd8a85b2 100644 --- a/ui/src/main/res/values/ids.xml +++ b/ui/src/main/res/values/ids.xml @@ -6,6 +6,12 @@ + + + + + + @@ -14,4 +20,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml index 7e43ad98f..659d07697 100644 --- a/ui/src/main/res/values/strings.xml +++ b/ui/src/main/res/values/strings.xml @@ -14,7 +14,7 @@ Add Account Add Transfer Method Bank Account - Bank Card + Debit Card The length of this field is exactly %d. %s is invalid. @@ -68,11 +68,11 @@ Bank Account - Bank Card - Wire Account + Debit Card + Wire Transfer Paper Check Prepaid Card - PayPal + PayPal Account \uE000 \uE005 @@ -81,9 +81,17 @@ \uE00A \uE021 + Account Holder + Account Information + Address + Contact Information + Identification + Intermediary Account + Search Hint Search Country Search Currency + Search Account Information - %s (%s) Transfer Method Information diff --git a/ui/src/main/res/values/styles.xml b/ui/src/main/res/values/styles.xml index b61828efc..887a6de77 100644 --- a/ui/src/main/res/values/styles.xml +++ b/ui/src/main/res/values/styles.xml @@ -106,6 +106,10 @@ @color/colorSecondaryDark + + + + + + diff --git a/ui/src/test/java/com/hyperwallet/android/ui/view/widget/DateUtilTest.java b/ui/src/test/java/com/hyperwallet/android/ui/view/widget/DateUtilTest.java new file mode 100644 index 000000000..d016de8af --- /dev/null +++ b/ui/src/test/java/com/hyperwallet/android/ui/view/widget/DateUtilTest.java @@ -0,0 +1,89 @@ +package com.hyperwallet.android.ui.view.widget; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import java.text.ParseException; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collection; + +@RunWith(RobolectricTestRunner.class) +public class DateUtilTest { + private final DateUtil mDateUtil = new DateUtil(); + + @Rule + public final ExpectedException mThrown = ExpectedException.none(); + + @Test + public void testConvertDateFromServerToWidgetFormat() throws Exception { + String serverDate = "2005-05-23"; + String widgetDate = "23 May 2005"; + assertThat(mDateUtil.convertDateFromServerToWidgetFormat(serverDate), is(widgetDate)); + } + + @Test + public void testBuildParamsDateFromServerToWidget_whenIncorrectDate() throws Exception { + mThrown.expect(ParseException.class); + mDateUtil.convertDateFromServerToWidgetFormat("1990-01"); + } + + @Test + public void testConvertDateFromServerToWidgetFormat_whenDateIsNullOrEmpty() throws Exception { + assertThat(mDateUtil.convertDateFromServerToWidgetFormat(""), is("")); + assertThat(mDateUtil.convertDateFromServerToWidgetFormat(null), is("")); + } + + @Test + public void testBuildParamsDateFromServerToCalendar_whenIncorrectDate() throws Exception { + mThrown.expect(ParseException.class); + mDateUtil.convertDateFromServerFormatToCalendar("123-32").getTime(); + } + + @Test + public void testConvertDateFromServerFormatToCalendar_whenDateIsNullOrEmpty() throws ParseException { + assertThat(mDateUtil.convertDateFromServerFormatToCalendar(null).getTime().toString(), + is(Calendar.getInstance().getTime().toString())); + assertThat(mDateUtil.convertDateFromServerFormatToCalendar("").getTime().toString(), + is(Calendar.getInstance().getTime().toString())); + } + + @Test + public void testConvertDateFromServerFormatToCalendar() throws ParseException { + String serverDate = "2005-05-23"; + final Calendar mayCalendar = Calendar.getInstance(); + mayCalendar.set(2005, 4, 23, 0, 0, 0); + assertThat(mDateUtil.convertDateFromServerFormatToCalendar(serverDate).getTime().toString(), + is(mayCalendar.getTime().toString())); + } + + @Test + public void testBuildDateFromDateDialogToServerFormat() { + String widgetDate; + int year; + int month; + int dayOfMonth; + Collection inputParamList = buildParamsFromDialogToServer(); + for (Object[] item : inputParamList) { + year = (int) item[0]; + month = (int) item[1]; + dayOfMonth = (int) item[2]; + widgetDate = (String) item[3]; + assertThat(mDateUtil.buildDateFromDateDialogToServerFormat(year, month, dayOfMonth), is(widgetDate)); + } + } + + private Collection buildParamsFromDialogToServer() { + return Arrays.asList(new Object[][]{ + {1900, 0, 1, "1900-01-01"}, + {2000, 11, 31, "2000-12-31"}, + {2001, 10, 13, "2001-11-13"} + }); + } +} \ No newline at end of file From 3899d1280c8e261cffaa14c39465d382ef21e99f Mon Sep 17 00:00:00 2001 From: Shyang Koong Date: Mon, 3 Jun 2019 14:13:32 -0700 Subject: [PATCH 010/177] Updating test dependencies (#32) --- ui/build.gradle | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/build.gradle b/ui/build.gradle index 1544467c9..7fdbb6b2d 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -45,23 +45,23 @@ dependencies { implementation "androidx.appcompat:appcompat:1.0.2" implementation "com.google.android.material:material:1.0.0" implementation "androidx.constraintlayout:constraintlayout:1.1.3" - implementation "androidx.test.espresso:espresso-idling-resource:3.1.1" + implementation "androidx.test.espresso:espresso-idling-resource:3.2.0" implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.recyclerview:recyclerview:1.0.0" api "com.hyperwallet.android:core-sdk:1.0.0-beta03-SNAPSHOT" - androidTestImplementation "androidx.test.ext:junit:1.1.0" - androidTestImplementation "androidx.test:runner:1.1.1" - androidTestImplementation "androidx.test:rules:1.1.1" - androidTestImplementation "androidx.test.espresso:espresso-core:3.1.1" - androidTestImplementation "androidx.test.espresso:espresso-contrib:3.1.1" - androidTestImplementation "androidx.test.espresso:espresso-intents:3.1.1" + androidTestImplementation "androidx.test.ext:junit:1.1.1" + androidTestImplementation "androidx.test:runner:1.2.0" + androidTestImplementation "androidx.test:rules:1.2.0" + androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0" + androidTestImplementation "androidx.test.espresso:espresso-contrib:3.2.0" + androidTestImplementation "androidx.test.espresso:espresso-intents:3.2.0" androidTestImplementation "com.squareup.okhttp3:mockwebserver:3.11.0" androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:1.6.3" androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:1.6.3" - testImplementation group: 'org.mockito', name: 'mockito-core', version: "2.25.0" + testImplementation group: 'org.mockito', name: 'mockito-core', version: "2.27.0" testImplementation group: 'pl.pragmatists', name: 'JUnitParams', version: "1.1.1" testImplementation "org.robolectric:robolectric:4.1" testImplementation "com.squareup.okhttp3:mockwebserver:3.11.0" From a8ecd82d1573019f06966ec1bcac2388e36f308d Mon Sep 17 00:00:00 2001 From: Shyang Koong Date: Mon, 3 Jun 2019 15:00:06 -0700 Subject: [PATCH 011/177] HW-53053: Fixing ui tests (#33) --- .../ui/AddTransferMethodTest.java | 32 ++--- .../transfermethod/ui/BankAccountTest.java | 120 ++++++++++++------ .../transfermethod/ui/BankCardTest.java | 80 ++++++++---- .../android/transfermethod/ui/PayPalTest.java | 45 ++++--- .../android/util/EspressoUtils.java | 59 ++++++--- 5 files changed, 216 insertions(+), 120 deletions(-) diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java index c4af970ff..61cd031aa 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java @@ -2,8 +2,7 @@ import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; -import static androidx.test.espresso.action.ViewActions.typeText; +import static androidx.test.espresso.action.ViewActions.replaceText; import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.RootMatchers.isDialog; @@ -130,12 +129,9 @@ public void testAddTransferMethod_displaysErrorDialogOnDuplicateAccountFailure() mActivityTestRule.launchActivity(null); - onView(withId(R.id.branchId)) - .perform(typeText(ROUTING_NUMBER)).perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountId)) - .perform(typeText(String.valueOf(ACCOUNT_NUMBER))) - .perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountPurpose)).perform(click()); + onView(withId(R.id.branchId)).perform(nestedScrollTo(), replaceText(ROUTING_NUMBER)); + onView(withId(R.id.bankAccountId)).perform(nestedScrollTo(), replaceText(ACCOUNT_NUMBER)); + onView(withId(R.id.bankAccountPurpose)).perform(nestedScrollTo(), click()); onView(allOf(withId(R.id.select_name), withText("Savings"))).perform(click()); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); @@ -165,12 +161,9 @@ public void testAddTransferMethod_displaysUnexpectedErrorDialogOnException() { mActivityTestRule.launchActivity(null); - onView(withId(R.id.branchId)).perform(typeText(ROUTING_NUMBER)).perform( - closeSoftKeyboard()); - onView(withId(R.id.bankAccountId)) - .perform(typeText(ACCOUNT_NUMBER)) - .perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountPurpose)).perform(click()); + onView(withId(R.id.branchId)).perform(nestedScrollTo(), replaceText(ROUTING_NUMBER)); + onView(withId(R.id.bankAccountId)).perform(nestedScrollTo(), replaceText(ACCOUNT_NUMBER)); + onView(withId(R.id.bankAccountPurpose)).perform(nestedScrollTo(), click()); onView(allOf(withId(R.id.select_name), withText("Savings"))).perform(click()); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); @@ -193,14 +186,9 @@ public void testAddTransferMethod_displaysNetworkErrorDialogOnConnectionTimeout( mActivityTestRule.launchActivity(null); - onView(withId(R.id.branchId)) - .perform(typeText(ROUTING_NUMBER)) - .perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountId)) - .perform(typeText(ACCOUNT_NUMBER)) - .perform(closeSoftKeyboard()); - - onView(withId(R.id.bankAccountPurpose)).perform(click()); + onView(withId(R.id.branchId)).perform(nestedScrollTo(), replaceText(ROUTING_NUMBER)); + onView(withId(R.id.bankAccountId)).perform(nestedScrollTo(), replaceText(ACCOUNT_NUMBER)); + onView(withId(R.id.bankAccountPurpose)).perform(nestedScrollTo(), click()); onView(allOf(withId(R.id.select_name), withText("Savings"))).perform(click()); // initiate test diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java index 3a6e23137..75b62af11 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java @@ -2,13 +2,11 @@ import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; -import static androidx.test.espresso.action.ViewActions.typeText; +import static androidx.test.espresso.action.ViewActions.replaceText; import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; -import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withParent; @@ -28,6 +26,7 @@ import static com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount.Purpose.SAVINGS; import static com.hyperwallet.android.util.EspressoUtils.hasEmptyText; import static com.hyperwallet.android.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.util.EspressoUtils.hasNoErrorText; import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; import static com.hyperwallet.android.util.EspressoUtils.withHint; @@ -123,8 +122,9 @@ public void testAddTransferMethod_displaysElementsOnTmcResponse() { onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) .check(matches(withText(R.string.title_add_bank_account))); - onView(allOf(withId(R.id.section_header_title), withText("Account Information - United States (USD)"))).check( - matches(isDisplayed())); + onView(allOf(withId(R.id.section_header_title), withText("Account Information - United States (USD)"))) + .perform(nestedScrollTo()) + .check(matches(isDisplayed())); onView(withId(R.id.branchId)).perform(nestedScrollTo()).check(matches(isDisplayed())); onView(withId(R.id.branchIdLabel)).check(matches(isDisplayed())); onView(withId(R.id.branchIdLabel)).check(matches(withHint("Routing Number"))); @@ -133,11 +133,11 @@ public void testAddTransferMethod_displaysElementsOnTmcResponse() { onView(withId(R.id.bankAccountIdLabel)).check(matches(withHint("Account Number"))); onView(withId(R.id.bankAccountPurpose)).perform(nestedScrollTo()).check(matches(isDisplayed())); onView(withId(R.id.bankAccountPurposeLabel)).check(matches(isDisplayed())); - onView(withId(R.id.bankAccountPurposeLabel)).check( - matches(withHint("Account Type"))); + onView(withId(R.id.bankAccountPurposeLabel)).check(matches(withHint("Account Type"))); - onView(allOf(withId(R.id.section_header_title), withText("Account Holder"))).perform(nestedScrollTo()).check( - matches(isDisplayed())); + onView(allOf(withId(R.id.section_header_title), withText("Account Holder"))) + .perform(nestedScrollTo()) + .check(matches(isDisplayed())); onView(withId(R.id.firstName)).perform(nestedScrollTo()).check(matches(isDisplayed())); onView(withId(R.id.firstNameLabel)).check(matches(isDisplayed())); onView(withId(R.id.firstNameLabel)).check(matches(withHint("First Name"))); @@ -151,8 +151,9 @@ public void testAddTransferMethod_displaysElementsOnTmcResponse() { onView(withId(R.id.dateOfBirthLabel)).check(matches(isDisplayed())); onView(withId(R.id.dateOfBirthLabel)).check(matches(withHint("Date of Birth"))); - onView(allOf(withId(R.id.section_header_title), withText("Contact Information"))).perform( - nestedScrollTo()).check(matches(isDisplayed())); + onView(allOf(withId(R.id.section_header_title), withText("Contact Information"))) + .perform(nestedScrollTo()) + .check(matches(isDisplayed())); onView(withId(R.id.phoneNumber)).perform(nestedScrollTo()).check(matches(isDisplayed())); onView(withId(R.id.phoneNumberLabel)).check(matches(isDisplayed())); onView(withId(R.id.phoneNumberLabel)).check(matches(withHint("Phone Number"))); @@ -160,8 +161,9 @@ public void testAddTransferMethod_displaysElementsOnTmcResponse() { onView(withId(R.id.mobileNumberLabel)).check(matches(isDisplayed())); onView(withId(R.id.mobileNumberLabel)).check(matches(withHint("Mobile Number"))); - onView(allOf(withId(R.id.section_header_title), withText("Address"))).perform(nestedScrollTo()).check( - matches(isDisplayed())); + onView(allOf(withId(R.id.section_header_title), withText("Address"))) + .perform(nestedScrollTo()) + .check(matches(isDisplayed())); onView(withId(R.id.country)).perform(nestedScrollTo()).check(matches(isDisplayed())); onView(withId(R.id.countryLabel)).check(matches(isDisplayed())); onView(withId(R.id.countryLabel)).check(matches(withHint("Country"))); @@ -214,7 +216,7 @@ public void testAddTransferMethod_verifyDefaultValues() { onView(withId(R.id.firstName)).check(matches(withText("Brody"))); onView(withId(R.id.middleName)).check(matches(hasEmptyText())); onView(withId(R.id.lastName)).check(matches(withText("Nehru"))); - onView(withId(R.id.dateOfBirth)).check(matches(withText("2000-01-01"))); + onView(withId(R.id.dateOfBirth)).check(matches(withText("January 01, 2000"))); onView(withId(R.id.phoneNumber)).check(matches(withText("+1 604 6666666"))); onView(withId(R.id.mobileNumber)).check(matches(withText("604 666 6666"))); @@ -298,11 +300,9 @@ public void onReceive(Context context, Intent intent) { LocalBroadcastManager.getInstance(mActivityTestRule.getActivity().getApplicationContext()) .registerReceiver(br, new IntentFilter("ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED")); - onView(withId(R.id.branchId)) - .perform(typeText(ROUTING_NUMBER)).perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountId)) - .perform(typeText(ACCOUNT_NUMBER)).perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountPurpose)).perform(click()); + onView(withId(R.id.branchId)).perform(nestedScrollTo(), replaceText(ROUTING_NUMBER)); + onView(withId(R.id.bankAccountId)).perform(nestedScrollTo(), replaceText(ACCOUNT_NUMBER)); + onView(withId(R.id.bankAccountPurpose)).perform(nestedScrollTo(), click()); onView(withId(R.id.search_button)).check(doesNotExist()); onView(withId(R.id.input_selection_list)).check(new RecyclerViewCountAssertion(2)); onView(allOf(withId(R.id.select_name), withText("Savings"))).perform(click()); @@ -321,21 +321,53 @@ public void onReceive(Context context, Intent intent) { @Test public void testAddTransferMethod_returnsErrorOnInvalidPattern() { mActivityTestRule.launchActivity(null); - // Number input should not allow non numeric values - onView(withId(R.id.branchId)).perform(typeText("a12-345")); - onView(withId(R.id.branchId)).check(matches(withText("12345"))); + + onView(withId(R.id.bankAccountId)).perform(nestedScrollTo(), replaceText("ewrd{123")); + onView(withId(R.id.branchId)).perform(nestedScrollTo(), replaceText("{dfghfgh}")); + onView(withId(R.id.firstName)).perform(nestedScrollTo(), replaceText("ewrd{1{2")); + onView(withId(R.id.lastName)).perform(nestedScrollTo(), replaceText("ewrd{1{2345")); + onView(withId(R.id.addressLine1)).perform(nestedScrollTo(), replaceText("950 {G}ranville Street")); + onView(withId(R.id.city)).perform(nestedScrollTo(), replaceText("Vancouve{r}")); + onView(withId(R.id.stateProvince)).perform(nestedScrollTo(), replaceText("df{r}")); + onView(withId(R.id.postalCode)).perform(nestedScrollTo(), replaceText("df{r}")); + + onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); + + onView(withId(R.id.branchIdLabel)) + .check(matches(hasErrorText("is invalid length or format."))); + onView(withId(R.id.bankAccountIdLabel)) + .check(matches(hasErrorText("is invalid length or format."))); + onView(withId(R.id.firstNameLabel)) + .check(matches(hasErrorText("is invalid length or format."))); + onView(withId(R.id.lastNameLabel)) + .check(matches(hasErrorText("is invalid length or format."))); + onView(withId(R.id.addressLine1Label)) + .check(matches(hasErrorText("is invalid length or format."))); + onView(withId(R.id.cityLabel)) + .check(matches(hasErrorText("is invalid length or format."))); + onView(withId(R.id.stateProvinceLabel)) + .check(matches(hasErrorText("is invalid length or format."))); + onView(withId(R.id.postalCodeLabel)) + .check(matches(hasErrorText("is invalid length or format."))); } @Test public void testAddTransferMethod_returnsErrorOnInvalidPresence() { mActivityTestRule.launchActivity(null); - onView(withId(R.id.branchId)).perform(click()).perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountId)).perform(click()).perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountPurpose)).perform(click()); - - onView(allOf(withContentDescription(R.string.abc_action_bar_up_description), - withParent(withId(R.id.input_selection_toolbar)))).perform(click()); + onView(withId(R.id.branchId)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.bankAccountId)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.bankAccountPurpose)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.firstName)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.middleName)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.lastName)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.dateOfBirth)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.phoneNumber)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.mobileNumber)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.addressLine1)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.city)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.stateProvince)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.postalCode)).perform(nestedScrollTo(), replaceText("")); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); @@ -345,16 +377,31 @@ public void testAddTransferMethod_returnsErrorOnInvalidPresence() { .check(matches(hasErrorText("You must provide a value for this field"))); onView(withId(R.id.bankAccountPurposeLabel)) .check(matches(hasErrorText("You must provide a value for this field"))); + onView(withId(R.id.firstNameLabel)) + .check(matches(hasErrorText("You must provide a value for this field"))); + onView(withId(R.id.lastNameLabel)) + .check(matches(hasErrorText("You must provide a value for this field"))); + onView(withId(R.id.addressLine1Label)) + .check(matches(hasErrorText("You must provide a value for this field"))); + onView(withId(R.id.cityLabel)) + .check(matches(hasErrorText("You must provide a value for this field"))); + onView(withId(R.id.stateProvinceLabel)) + .check(matches(hasErrorText("You must provide a value for this field"))); + onView(withId(R.id.postalCodeLabel)) + .check(matches(hasErrorText("You must provide a value for this field"))); + + onView(withId(R.id.middleNameLabel)).check(matches(hasNoErrorText())); + onView(withId(R.id.dateOfBirthLabel)).check(matches(hasNoErrorText())); + onView(withId(R.id.phoneNumberLabel)).check(matches(hasNoErrorText())); + onView(withId(R.id.mobileNumberLabel)).check(matches(hasNoErrorText())); } @Test public void testAddTransferMethod_returnsErrorOnInvalidLength() { mActivityTestRule.launchActivity(null); - onView(withId(R.id.branchId)) - .perform(typeText("2111795311")).perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountId)) - .perform(typeText("1")).perform(closeSoftKeyboard()); + onView(withId(R.id.branchId)).perform(nestedScrollTo(), replaceText("2111795311")); + onView(withId(R.id.bankAccountId)).perform(nestedScrollTo(), replaceText("1")); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); @@ -371,12 +418,9 @@ public void testAddTransferMethod_displaysErrorOnInvalidRoutingNumber() { mActivityTestRule.launchActivity(null); - onView(withId(R.id.branchId)) - .perform(typeText(INVALID_ROUTING_NUMBER)).perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountId)) - .perform(typeText(ACCOUNT_NUMBER)) - .perform(closeSoftKeyboard()); - onView(withId(R.id.bankAccountPurpose)).perform(click()); + onView(withId(R.id.branchId)).perform(nestedScrollTo(), replaceText(INVALID_ROUTING_NUMBER)); + onView(withId(R.id.bankAccountId)).perform(nestedScrollTo(), replaceText(ACCOUNT_NUMBER)); + onView(withId(R.id.bankAccountPurpose)).perform(nestedScrollTo(), click()); onView(allOf(withId(R.id.select_name), withText("Checking"))).perform(click()); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java index 7ec4d7326..3003b01b3 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java @@ -2,11 +2,11 @@ import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; -import static androidx.test.espresso.action.ViewActions.pressImeActionButton; +import static androidx.test.espresso.action.ViewActions.replaceText; import static androidx.test.espresso.action.ViewActions.typeText; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withParent; @@ -22,6 +22,7 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.concurrent.TimeUnit.SECONDS; +import static com.hyperwallet.android.util.EspressoUtils.hasEmptyText; import static com.hyperwallet.android.util.EspressoUtils.hasErrorText; import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; import static com.hyperwallet.android.util.EspressoUtils.withHint; @@ -122,16 +123,19 @@ public void unregisterIdlingResource() { public void testAddTransferMethod_displaysElementsOnTmcResponse() { mActivityTestRule.launchActivity(null); - onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))).check( - matches(withText(R.string.title_add_bank_card))); + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_add_bank_card))); - onView(withId(R.id.cardNumber)).check(matches(isDisplayed())); + onView(allOf(withId(R.id.section_header_title), withText("Account Information - United States (USD)"))) + .perform(nestedScrollTo()) + .check(matches(isDisplayed())); + onView(withId(R.id.cardNumber)).perform(nestedScrollTo()).check(matches(isDisplayed())); onView(withId(R.id.cardNumberLabel)).check(matches(isDisplayed())); onView(withId(R.id.cardNumberLabel)).check(matches(withHint(CARD_NUMBER_LABEL))); - onView(withId(R.id.dateOfExpiry)).check(matches(isDisplayed())); + onView(withId(R.id.dateOfExpiry)).perform(nestedScrollTo()).check(matches(isDisplayed())); onView(withId(R.id.dateOfExpiryLabel)).check(matches(isDisplayed())); onView(withId(R.id.dateOfExpiryLabel)).check(matches(withHint(EXPIRY_DATE_LABEL))); - onView(withId(R.id.cvv)).check(matches(isDisplayed())); + onView(withId(R.id.cvv)).perform(nestedScrollTo()).check(matches(isDisplayed())); onView(withId(R.id.cvvLabel)).check(matches(isDisplayed())); onView(withId(R.id.cvvLabel)).check(matches(withHint(CVV_LABEL))); @@ -160,6 +164,24 @@ public void testAddTransferMethod_displaysFeeElementsOnTmcResponse() { // onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("1 - 2 Business Days"))); } + @Test + public void testAddTransferMethod_verifyDefaultValues() { + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.cardNumber)).check(matches(hasEmptyText())); + onView(withId(R.id.dateOfExpiry)).check(matches(hasEmptyText())); + onView(withId(R.id.cvv)).check(matches(hasEmptyText())); + } + + @Test + public void testAddTransferMethod_verifyEditableFields() { + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.cardNumber)).check(matches(isEnabled())); + onView(withId(R.id.dateOfExpiry)).check(matches(isEnabled())); + onView(withId(R.id.cvv)).check(matches(isEnabled())); + } + @Test public void testAddTransferMethod_returnsTokenOnBankCardCreation() throws InterruptedException { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_CREATED).withBody(sResourceManager @@ -185,12 +207,11 @@ public void onReceive(Context context, Intent intent) { LocalBroadcastManager.getInstance(mActivityTestRule.getActivity().getApplicationContext()) .registerReceiver(br, new IntentFilter("ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED")); - onView(withId(R.id.cardNumber)).perform(typeText(VALID_CARD_NUMBER)).perform(closeSoftKeyboard()); - onView(withId(R.id.dateOfExpiry)).perform(typeText(VALID_EXPIRATION_DATE)).perform(closeSoftKeyboard()); - + onView(withId(R.id.cardNumber)).perform(nestedScrollTo(), replaceText(VALID_CARD_NUMBER)); + // Type text here instead to trigger auto-formatting + onView(withId(R.id.dateOfExpiry)).perform(nestedScrollTo(), typeText(VALID_EXPIRATION_DATE)); onView(withId(R.id.dateOfExpiry)).check(matches(withText(VALID_EXPIRATION_DATE_FORMATTED))); - - onView(withId(R.id.cvv)).perform(typeText(VALID_CVV)).perform(closeSoftKeyboard()); + onView(withId(R.id.cvv)).perform(nestedScrollTo(), replaceText(VALID_CVV)); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); gate.await(5, SECONDS); @@ -198,8 +219,8 @@ public void onReceive(Context context, Intent intent) { assertThat("Result code is incorrect", mActivityTestRule.getActivityResult().getResultCode(), is(Activity.RESULT_OK)); - LocalBroadcastManager.getInstance(mActivityTestRule.getActivity().getApplicationContext()).unregisterReceiver( - br); + LocalBroadcastManager.getInstance( + mActivityTestRule.getActivity().getApplicationContext()).unregisterReceiver(br); assertThat("Action is not broadcasted", gate.getCount(), is(0L)); } @@ -207,20 +228,24 @@ public void onReceive(Context context, Intent intent) { public void testAddTransferMethod_returnsErrorOnInvalidPattern() { mActivityTestRule.launchActivity(null); - onView(withId(R.id.dateOfExpiry)) - .perform(typeText(INVALID_PATTERN_EXPIRATION_DATE)) - .perform(closeSoftKeyboard(), pressImeActionButton()); + onView(withId(R.id.cardNumber)).perform(nestedScrollTo(), replaceText("abc12341234cb")); + onView(withId(R.id.dateOfExpiry)).perform(nestedScrollTo(), replaceText(INVALID_PATTERN_EXPIRATION_DATE)); + onView(withId(R.id.cvv)).perform(nestedScrollTo(), replaceText("9-09")); + onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); + + onView(withId(R.id.cardNumberLabel)).check(matches(hasErrorText("is invalid length or format."))); onView(withId(R.id.dateOfExpiryLabel)).check(matches(hasErrorText("Expiry Date is invalid."))); + onView(withId(R.id.cvvLabel)).check(matches(hasErrorText("is invalid length or format."))); } @Test public void testAddTransferMethod_returnsErrorOnInvalidPresence() { mActivityTestRule.launchActivity(null); - onView(withId(R.id.cardNumber)).perform(click()).perform(closeSoftKeyboard()); - onView(withId(R.id.dateOfExpiry)).perform(click()).perform(closeSoftKeyboard()); - onView(withId(R.id.cvv)).perform(click()).perform(closeSoftKeyboard()); + onView(withId(R.id.cardNumber)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.dateOfExpiry)).perform(nestedScrollTo(), replaceText("")); + onView(withId(R.id.cvv)).perform(nestedScrollTo(), replaceText("")); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); @@ -236,11 +261,18 @@ public void testAddTransferMethod_returnsErrorOnInvalidPresence() { public void testAddTransferMethod_returnsErrorOnInvalidLength() { mActivityTestRule.launchActivity(null); - onView(withId(R.id.cardNumber)).perform(typeText(WRONG_LENGTH_CARD_NUMBER)).perform(closeSoftKeyboard()); + onView(withId(R.id.cardNumber)).perform(nestedScrollTo(), replaceText(WRONG_LENGTH_CARD_NUMBER)); + onView(withId(R.id.dateOfExpiry)).perform(nestedScrollTo(), replaceText("1")); + onView(withId(R.id.cvv)).perform(nestedScrollTo(), replaceText("1")); + onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); onView(withId(R.id.cardNumberLabel)).check( matches(hasErrorText("The minimum length of this field is 13 and maximum length is 19."))); + onView(withId(R.id.dateOfExpiryLabel)).check( + matches(hasErrorText("The length of this field is exactly 5."))); + onView(withId(R.id.cvvLabel)).check( + matches(hasErrorText("The minimum length of this field is 3 and maximum length is 4."))); } @Test @@ -250,9 +282,9 @@ public void testAddTransferMethod_returnsErrorOnInvalidCardNumber() { mActivityTestRule.launchActivity(null); - onView(withId(R.id.cardNumber)).perform(typeText(NOT_VALID_CARD_NUMBER)).perform(closeSoftKeyboard()); - onView(withId(R.id.dateOfExpiry)).perform(typeText(VALID_EXPIRATION_DATE)).perform(closeSoftKeyboard()); - onView(withId(R.id.cvv)).perform(typeText(VALID_CVV)).perform(closeSoftKeyboard()); + onView(withId(R.id.cardNumber)).perform(nestedScrollTo(), replaceText(NOT_VALID_CARD_NUMBER)); + onView(withId(R.id.dateOfExpiry)).perform(nestedScrollTo(), replaceText(VALID_EXPIRATION_DATE)); + onView(withId(R.id.cvv)).perform(nestedScrollTo(), replaceText(VALID_CVV)); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); onView(withId(R.id.cardNumberLabel)).check(matches(hasErrorText( diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java index 6b888844c..ee49a0163 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java @@ -2,12 +2,12 @@ import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; -import static androidx.test.espresso.action.ViewActions.typeText; +import static androidx.test.espresso.action.ViewActions.replaceText; 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.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withParent; @@ -24,6 +24,7 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.concurrent.TimeUnit.SECONDS; +import static com.hyperwallet.android.util.EspressoUtils.hasEmptyText; import static com.hyperwallet.android.util.EspressoUtils.hasErrorText; import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; import static com.hyperwallet.android.util.EspressoUtils.withHint; @@ -112,10 +113,10 @@ public void unregisterIdlingResource() { public void testAddTransferMethod_displaysElementsOnTmcResponse() { mActivityTestRule.launchActivity(null); - onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))).check( - matches(withText(R.string.paypal_account))); + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.paypal_account))); - onView(withId(R.id.email)).check(matches(isDisplayed())); + onView(withId(R.id.email)).perform(nestedScrollTo()).check(matches(isDisplayed())); onView(withId(R.id.emailLabel)).check(matches(isDisplayed())); onView(withId(R.id.emailLabel)).check(matches(withHint("Email"))); @@ -123,6 +124,20 @@ public void testAddTransferMethod_displaysElementsOnTmcResponse() { matches(withText(R.string.button_create_transfer_method))); } + @Test + public void testAddTransferMethod_verifyDefaultValues() { + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.email)).check(matches(hasEmptyText())); + } + + @Test + public void testAddTransferMethod_verifyEditableFields() { + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.email)).check(matches(isEnabled())); + } + @Test public void testAddTransferMethod_displaysFeeElementsOnTmcResponse() { mActivityTestRule.launchActivity(null); @@ -161,33 +176,32 @@ public void onReceive(Context context, Intent intent) { HyperwalletTransferMethod transferMethod = intent.getParcelableExtra( "hyperwallet-local-broadcast-payload"); assertThat("Bank Account Id is incorrect", transferMethod.getField( - HyperwalletTransferMethod.TransferMethodFields.EMAIL), is("sunshine.carreiro@hyperwallet.com")); + HyperwalletTransferMethod.TransferMethodFields.EMAIL), + is("sunshine.carreiro@hyperwallet.com")); } }; LocalBroadcastManager.getInstance(mActivityTestRule.getActivity().getApplicationContext()) .registerReceiver(br, new IntentFilter("ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED")); - onView(withId(R.id.email)) - .perform(typeText("sunshine.carreiro@hyperwallet.com")) - .perform(closeSoftKeyboard()); - + onView(withId(R.id.email)).perform(nestedScrollTo(), replaceText("sunshine.carreiro@hyperwallet.com")); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); assertThat("Result code is incorrect", mActivityTestRule.getActivityResult().getResultCode(), is(Activity.RESULT_OK)); gate.await(5, SECONDS); - LocalBroadcastManager.getInstance(mActivityTestRule.getActivity().getApplicationContext()).unregisterReceiver( - br); + LocalBroadcastManager + .getInstance(mActivityTestRule.getActivity().getApplicationContext()).unregisterReceiver(br); assertThat("Action is not broadcasted", gate.getCount(), is(0L)); } @Test public void testAddTransferMethod_returnsErrorOnInvalidPattern() { mActivityTestRule.launchActivity(null); - // Number input should not allow non numeric values - onView(withId(R.id.email)).perform(typeText("abc1test")); + + onView(withId(R.id.email)).perform(nestedScrollTo(), replaceText("abc1test")); + onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); onView(withId(R.id.emailLabel)) @@ -211,8 +225,7 @@ public void testAddTransferMethod_displaysErrorOnInvalidEmailAddress() { mActivityTestRule.launchActivity(null); - onView(withId(R.id.email)) - .perform(typeText("invalidEmail@gmail.com")).perform(closeSoftKeyboard()); + onView(withId(R.id.email)).perform(nestedScrollTo(), replaceText("invalidEmail@gmail.com")); onView(withId(R.id.add_transfer_method_button)).perform(nestedScrollTo(), click()); // check dialog content diff --git a/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java b/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java index 28fb0b590..92a711f96 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java @@ -19,6 +19,8 @@ import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; +import java.util.Objects; + public class EspressoUtils { public static Matcher withHint(final String expectedHint) { @@ -30,8 +32,7 @@ public boolean matchesSafely(View view) { return false; } - String hint = ((TextInputLayout) view).getHint().toString(); - + String hint = Objects.toString(((TextInputLayout) view).getHint()); return expectedHint.equals(hint); } @@ -51,8 +52,7 @@ public boolean matchesSafely(View view) { return false; } - String errorMessage = ((TextInputLayout) view).getError().toString(); - + String errorMessage = Objects.toString(((TextInputLayout) view).getError()); return expectedErrorMessage.equals(errorMessage); } @@ -72,7 +72,7 @@ public boolean matchesSafely(View view) { return false; } String expectedErrorMessage = view.getResources().getString(resourceId); - String errorMessage = ((TextInputLayout) view).getError().toString(); + String errorMessage = Objects.toString(((TextInputLayout) view).getError()); return expectedErrorMessage.equals(errorMessage); } @@ -132,37 +132,56 @@ public void describeTo(Description description) { }; } - public static Matcher hasEmptyText() { + public static ViewAction nestedScrollTo() { + return ViewActions.actionWithAssertions(new NestedScrollToAction()); + } + + private static Bitmap getBitmap(Drawable drawable) { + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + + return bitmap; + } + + public static Matcher hasNoErrorText() { return new TypeSafeMatcher() { @Override public boolean matchesSafely(View view) { - if (!(view instanceof EditText)) { + if (!(view instanceof TextInputLayout)) { return false; } - String text = ((EditText) view).getText().toString(); - - return text.isEmpty(); + return ((TextInputLayout) view).getError() == null; } @Override public void describeTo(Description description) { + description.appendText("has no error text: "); } }; } - public static ViewAction nestedScrollTo() { - return ViewActions.actionWithAssertions(new NestedScrollToAction()); - } + public static Matcher hasEmptyText() { + return new TypeSafeMatcher() { - private static Bitmap getBitmap(Drawable drawable) { - Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof EditText)) { + return false; + } + String text = ((EditText) view).getText().toString(); - Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); + return text.isEmpty(); + } - return bitmap; + @Override + public void describeTo(Description description) { + } + }; } } + From 07dbbe4e1d08339f2189eb3b8d43b7ac4907cb56 Mon Sep 17 00:00:00 2001 From: Anna <48258136+azakrevska-epam@users.noreply.github.com> Date: Wed, 5 Jun 2019 01:04:43 +0300 Subject: [PATCH 012/177] HW-53053. Split ui modules (#29) --- android-library.gradle | 72 ++++++ build.gradle | 41 ++- common/.gitignore | 1 + common/build.gradle | 88 +++++++ common/config/jacoco-settings.gradle | 79 ++++++ common/config/lint.xml | 7 + common/proguard-rules.pro | 21 ++ common/src/main/AndroidManifest.xml | 2 + .../common}/util/EspressoIdlingResource.java | 2 +- .../error/DefaultErrorDialogFragment.java | 32 +-- .../DefaultErrorDialogFragmentContract.java | 2 +- .../DefaultErrorDialogFragmentPresenter.java | 2 +- .../view/error/OnNetworkErrorCallback.java | 6 +- .../src/main/res/drawable/circle.xml | 0 .../src/main/res/drawable/circle_white.xml | 0 .../res/drawable/content_border_bottom.xml | 0 .../drawable/content_border_top_bottom.xml | 0 .../main/res/drawable/horizontal_divider.xml | 0 .../drawable/ic_baseline_bug_report_24px.xml | 0 .../drawable/ic_baseline_cloud_off_24px.xml | 0 .../res/drawable/ic_baseline_warning_24px.xml | 0 .../src/main/res/drawable/ic_check_14dp.xml | 0 .../src/main/res/drawable/ic_close_14dp.xml | 0 .../drawable/ic_keyboard_arrow_down_12dp.xml | 0 .../drawable/ic_keyboard_arrow_left_12dp.xml | 0 .../drawable/ic_keyboard_arrow_right_12dp.xml | 0 .../res/drawable/ic_launcher_background.xml | 0 .../main/res/drawable/ic_placeholder_24dp.xml | 0 .../src/main/res/drawable/ic_search_24dp.xml | 0 .../main/res/drawable/ic_three_dots_16dp.xml | 0 .../src/main/res/drawable/ic_trash.xml | 0 {ui => common}/src/main/res/drawable/oval.xml | 0 .../res/drawable/view_border_top_bottom.xml | 0 {ui => common}/src/main/res/font/icomoon.ttf | Bin {ui => common}/src/main/res/values/colors.xml | 0 {ui => common}/src/main/res/values/dimens.xml | 0 common/src/main/res/values/strings.xml | 9 + common/src/main/res/values/styles.xml | 237 ++++++++++++++++++ ...faultErrorDialogFragmentPresenterTest.java | 10 +- receipt/.gitignore | 1 + receipt/build.gradle | 95 +++++++ receipt/config/jacoco-settings.gradle | 79 ++++++ receipt/config/lint.xml | 7 + receipt/proguard-rules.pro | 21 ++ receipt/src/main/AndroidManifest.xml | 2 + receipt/src/main/res/values/strings.xml | 103 ++++++++ settings.gradle | 2 +- ui/build.gradle | 102 ++------ ui/config/lint.xml | 2 + .../rule/HyperwalletMockWebServer.java | 8 +- .../ui/AddTransferMethodTest.java | 6 +- .../transfermethod/ui/BankAccountTest.java | 2 +- .../transfermethod/ui/BankCardTest.java | 2 +- .../android/transfermethod/ui/PayPalTest.java | 2 +- .../ui/SelectTransferMethodTest.java | 2 +- .../hyperwallet/android/ui/HyperwalletUi.java | 4 +- .../ui/repository/RepositoryFactory.java | 8 +- ...sferMethodConfigurationRepositoryImpl.java | 5 +- .../TransferMethodRepositoryImpl.java | 1 - .../AddTransferMethodActivity.java | 4 +- .../ListTransferMethodActivity.java | 4 +- .../SelectTransferMethodActivity.java | 4 +- .../SelectTransferMethodFragment.java | 10 +- .../view/CountrySelectionDialogFragment.java | 8 +- .../view/CurrencySelectionDialogFragment.java | 8 +- .../view/WidgetSelectionDialogFragment.java | 8 +- .../ui/view/widget/ExpiryDateWidget.java | 2 +- ui/src/main/res/values/strings.xml | 9 +- ui/src/main/res/values/styles.xml | 225 +---------------- .../TransferMethodRepositoryImplTest.java | 12 +- .../ui/repository/UserRepositoryImplTest.java | 12 +- .../AddTransferMethodPresenterTest.java | 9 +- .../ui/transfermethod/FeeFormatterTest.java | 5 +- .../ListTransferMethodPresenterTest.java | 17 +- .../SelectTransferMethodPresenterTest.java | 7 +- 75 files changed, 989 insertions(+), 420 deletions(-) create mode 100644 android-library.gradle create mode 100644 common/.gitignore create mode 100644 common/build.gradle create mode 100644 common/config/jacoco-settings.gradle create mode 100644 common/config/lint.xml create mode 100644 common/proguard-rules.pro create mode 100644 common/src/main/AndroidManifest.xml rename {ui/src/main/java/com/hyperwallet/android/ui => common/src/main/java/com/hyperwallet/android/common}/util/EspressoIdlingResource.java (93%) rename {ui/src/main/java/com/hyperwallet/android/ui => common/src/main/java/com/hyperwallet/android/common}/view/error/DefaultErrorDialogFragment.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => common/src/main/java/com/hyperwallet/android/common}/view/error/DefaultErrorDialogFragmentContract.java (97%) rename {ui/src/main/java/com/hyperwallet/android/ui => common/src/main/java/com/hyperwallet/android/common}/view/error/DefaultErrorDialogFragmentPresenter.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => common/src/main/java/com/hyperwallet/android/common}/view/error/OnNetworkErrorCallback.java (79%) rename {ui => common}/src/main/res/drawable/circle.xml (100%) rename {ui => common}/src/main/res/drawable/circle_white.xml (100%) rename {ui => common}/src/main/res/drawable/content_border_bottom.xml (100%) rename {ui => common}/src/main/res/drawable/content_border_top_bottom.xml (100%) rename {ui => common}/src/main/res/drawable/horizontal_divider.xml (100%) rename {ui => common}/src/main/res/drawable/ic_baseline_bug_report_24px.xml (100%) rename {ui => common}/src/main/res/drawable/ic_baseline_cloud_off_24px.xml (100%) rename {ui => common}/src/main/res/drawable/ic_baseline_warning_24px.xml (100%) rename {ui => common}/src/main/res/drawable/ic_check_14dp.xml (100%) rename {ui => common}/src/main/res/drawable/ic_close_14dp.xml (100%) rename {ui => common}/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml (100%) rename {ui => common}/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml (100%) rename {ui => common}/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml (100%) rename {ui => common}/src/main/res/drawable/ic_launcher_background.xml (100%) rename {ui => common}/src/main/res/drawable/ic_placeholder_24dp.xml (100%) rename {ui => common}/src/main/res/drawable/ic_search_24dp.xml (100%) rename {ui => common}/src/main/res/drawable/ic_three_dots_16dp.xml (100%) rename {ui => common}/src/main/res/drawable/ic_trash.xml (100%) rename {ui => common}/src/main/res/drawable/oval.xml (100%) rename {ui => common}/src/main/res/drawable/view_border_top_bottom.xml (100%) rename {ui => common}/src/main/res/font/icomoon.ttf (100%) mode change 100755 => 100644 rename {ui => common}/src/main/res/values/colors.xml (100%) rename {ui => common}/src/main/res/values/dimens.xml (100%) create mode 100644 common/src/main/res/values/strings.xml create mode 100644 common/src/main/res/values/styles.xml rename {ui/src/test/java/com/hyperwallet/android/ui => common/src/test/java/com/hyperwallet/android/common}/view/error/DefaultErrorDialogFragmentPresenterTest.java (92%) create mode 100644 receipt/.gitignore create mode 100644 receipt/build.gradle create mode 100644 receipt/config/jacoco-settings.gradle create mode 100644 receipt/config/lint.xml create mode 100644 receipt/proguard-rules.pro create mode 100644 receipt/src/main/AndroidManifest.xml create mode 100644 receipt/src/main/res/values/strings.xml diff --git a/android-library.gradle b/android-library.gradle new file mode 100644 index 000000000..620173287 --- /dev/null +++ b/android-library.gradle @@ -0,0 +1,72 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' +apply plugin: 'org.sonarqube' +apply from: "$projectDir/config/jacoco-settings.gradle" + +android { + compileSdkVersion compileVersion + defaultConfig { + minSdkVersion minVersion + targetSdkVersion targetVersion + versionCode codeVersion + versionName version + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunnerArgument "listener", "com.squareup.leakcanary.FailTestOnLeakRunListener" + } + + sourceSets { + androidTest { + resources.srcDirs += ['src/test/resources'] + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + } + } + + lintOptions { + abortOnError true + warningsAsErrors true + lintConfig file("config/lint.xml") + } +} + +task javadocs(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + failOnError false +} + +task javadocsJar(type: Jar, dependsOn: javadocs) { + classifier = 'javadoc' + from javadocs.destinationDir +} + +task sourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +dependencies { + implementation "com.google.android.material:material:$androidMaterialVersion" + api "com.hyperwallet.android:core-sdk:$hyperwalletCoreVersion" + + implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion" + + androidTestImplementation "androidx.test.ext:junit:$extJunitVerson" + androidTestImplementation "androidx.test:runner:$testRunnerVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" + + testImplementation group: 'org.mockito', name: 'mockito-core', version: "$mockitoVersion" + testImplementation group: 'pl.pragmatists', name: 'JUnitParams', version: "$junitParamsVersion" +} + + + diff --git a/build.gradle b/build.gradle index b079d8d65..3df2d26b2 100644 --- a/build.gradle +++ b/build.gradle @@ -5,12 +5,12 @@ buildscript { google() jcenter() mavenLocal() - + } dependencies { classpath 'com.android.tools.build:gradle:3.3.2' classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7" - + // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -21,12 +21,45 @@ allprojects { google() jcenter() mavenLocal() - + } project.version = "1.0.0-beta03-SNAPSHOT" + +} + +subprojects { + + ext { + hyperwalletGroupId = 'com.hyperwallet.android' + + compileVersion = 28 + minVersion = 21 + targetVersion = 28 + codeVersion = 1 + + hyperwalletCoreVersion = '1.0.0-beta03-SNAPSHOT' + // + androidMaterialVersion = '1.0.0' + appcompatVersion = '1.0.2' + constraintlayoutVersion = '1.1.3' + legacySupportV4Version = '1.0.0' + recycleViewVersion = '1.0.0' + //Testing + extJunitVerson = '1.1.1' + testRunnerVersion = '1.2.0' + testRulesVersion = '1.2.0' + espressoVersion = '3.2.0' + mockServerVersion = '3.11.0' + leakcanaryVersion = '1.6.3' + mockitoVersion = '2.27.0' + junitParamsVersion = '1.1.1' + robolectricVersion = '4.1' + mockWebServerVersion = '3.11.0' + } + } task clean(type: Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/common/.gitignore b/common/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/common/.gitignore @@ -0,0 +1 @@ +/build diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 000000000..e4df818b5 --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,88 @@ +apply from: "$rootProject.projectDir/android-library.gradle" + + +def aarFile = file("$buildDir/outputs/aar/common-$version" + ".aar") +def aarArtifact = artifacts.add('archives', aarFile) { + type 'aar' +} + +def isReleaseVersion = !version.endsWith('SNAPSHOT') + +publishing { + + repositories { + maven { + def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2" + def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots" + url = isReleaseVersion ? releasesRepoUrl : snapshotsRepoUrl + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + + publications { + hyperwalletCommonUi(MavenPublication) { + groupId = hyperwalletGroupId + artifactId = 'common' + version = version + + artifact(sourcesJar) + artifact(javadocsJar) + artifact(aarArtifact) + + pom { + name = 'Hyperwallet Android Common UI SDK' + description = 'Hyperwallet Common UI SDK for Android to integrate with Hyperwallet Platform' + url = 'https://github.com/hyperwallet/hyperwallet-android-ui-sdk' + pom.withXml { + def dependenciesNode = asNode().appendNode('dependencies') + configurations.implementation.allDependencies.each { + def dependencyNode = dependenciesNode.appendNode('dependency') + dependencyNode.appendNode('groupId', it.group) + dependencyNode.appendNode('artifactId', it.name) + dependencyNode.appendNode('version', it.version) + } + } + licenses { + license { + name = 'MIT License' + url = 'http://www.opensource.org/licenses/MIT' + } + } + developers { + developer { + id = 'devs' + name = 'Hyperwallet Developers' + } + } + scm { + connection = 'scm:git:git://github.com/hyperwallet/hyperwallet-android-ui-sdk.git' + developerConnection = 'scm:git:git://github.com/hyperwallet/hyperwallet-android-ui-sdk.git' + url = 'https://github.com/hyperwallet/hyperwallet-android-ui-sdk' + } + } + } + } +} + +tasks.withType(Sign) { + onlyIf { + isReleaseVersion && sonatypeUsername?.trim() && sonatypePassword?.trim() + } +} + +signing { + sign publishing.publications.hyperwalletCommonUi +} + +sonarqube { + properties { + def libraries = project.android.sdkDirectory.getPath() + "/platforms/android-28/android.jar" + property "sonar.sources", "src/main/java" + property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android" + property "sonar.libraries", libraries + property "sonar.projectName", "android-ui-sdk-common" + } +} \ No newline at end of file diff --git a/common/config/jacoco-settings.gradle b/common/config/jacoco-settings.gradle new file mode 100644 index 000000000..7ce61b7aa --- /dev/null +++ b/common/config/jacoco-settings.gradle @@ -0,0 +1,79 @@ +apply plugin: 'jacoco' + +final def jacocoVersion = "0.8.2" + +jacoco { + toolVersion = jacocoVersion +} + +android { + testOptions { + unitTests { + includeAndroidResources = true + returnDefaultValues = true + } + unitTests.all { + jacoco { + includeNoLocationClasses = true + } + } + } +} + +def fileFilter = ['**/BuildConfig.*'] + +def debugClassPaths = [ + '**/intermediates/javac/dev/*/classes/**' +] + +final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] + +task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { + + group = 'Reporting' + description = 'Generate Jacoco coverage reports.' + + reports { + html { + enabled = true + destination file("$buildDir/reports/jacoco") + } + } + + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${buildDir}/jacoco/testDevUnitTest.exec") +} + +task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { + + group = 'Verification' + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") + + violationRules { + setFailOnViolation(true) + + rule { + element = 'CLASS' + limit { + value = 'COVEREDRATIO' + counter = 'BRANCH' + minimum = 0.65 + } + } + } +} + diff --git a/common/config/lint.xml b/common/config/lint.xml new file mode 100644 index 000000000..3c83d4bb5 --- /dev/null +++ b/common/config/lint.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/common/proguard-rules.pro b/common/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/common/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/common/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml new file mode 100644 index 000000000..72af9106f --- /dev/null +++ b/common/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/ui/src/main/java/com/hyperwallet/android/ui/util/EspressoIdlingResource.java b/common/src/main/java/com/hyperwallet/android/common/util/EspressoIdlingResource.java similarity index 93% rename from ui/src/main/java/com/hyperwallet/android/ui/util/EspressoIdlingResource.java rename to common/src/main/java/com/hyperwallet/android/common/util/EspressoIdlingResource.java index 61fbcbf40..92e6cf3a4 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/util/EspressoIdlingResource.java +++ b/common/src/main/java/com/hyperwallet/android/common/util/EspressoIdlingResource.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.util; +package com.hyperwallet.android.common.util; import androidx.test.espresso.IdlingResource; import androidx.test.espresso.idling.CountingIdlingResource; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragment.java b/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragment.java similarity index 98% rename from ui/src/main/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragment.java rename to common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragment.java index fd1938311..b3ea55029 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragment.java +++ b/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragment.java @@ -14,7 +14,7 @@ * 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.view.error; +package com.hyperwallet.android.common.view.error; import static com.hyperwallet.android.ExceptionMapper.EC_AUTHENTICATION_TOKEN_PROVIDER_EXCEPTION; import static com.hyperwallet.android.ExceptionMapper.EC_IO_EXCEPTION; @@ -33,7 +33,7 @@ import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentManager; -import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.common.R; import com.hyperwallet.android.model.HyperwalletError; import java.util.ArrayList; @@ -55,6 +55,20 @@ public DefaultErrorDialogFragment() { setRetainInstance(true); } + /** + * Builds Hyperwallet Error Dialogue + * + * @param errors List of Errors @see {@link Error} + */ + public static DefaultErrorDialogFragment newInstance(@NonNull List errors) { + Bundle bundle = new Bundle(); + bundle.putParcelableArrayList(ARGUMENT_ERROR_KEY, new ArrayList<>(errors)); + + DefaultErrorDialogFragment errorDialogFragment = new DefaultErrorDialogFragment(); + errorDialogFragment.setArguments(bundle); + return errorDialogFragment; + } + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -70,20 +84,6 @@ public void onCancel(DialogInterface dialog) { requireActivity().finish(); } - /** - * Builds Hyperwallet Error Dialogue - * - * @param errors List of Errors @see {@link Error} - */ - public static DefaultErrorDialogFragment newInstance(@NonNull List errors) { - Bundle bundle = new Bundle(); - bundle.putParcelableArrayList(ARGUMENT_ERROR_KEY, new ArrayList<>(errors)); - - DefaultErrorDialogFragment errorDialogFragment = new DefaultErrorDialogFragment(); - errorDialogFragment.setArguments(bundle); - return errorDialogFragment; - } - public void show(@NonNull FragmentManager manager) { show(manager, TAG); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragmentContract.java b/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentContract.java similarity index 97% rename from ui/src/main/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragmentContract.java rename to common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentContract.java index fa7950b6b..6fd3db51c 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragmentContract.java +++ b/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentContract.java @@ -14,7 +14,7 @@ * 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.view.error; +package com.hyperwallet.android.common.view.error; import android.content.res.Resources; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragmentPresenter.java b/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenter.java similarity index 98% rename from ui/src/main/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragmentPresenter.java rename to common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenter.java index 53103fdd5..b9f493359 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragmentPresenter.java +++ b/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenter.java @@ -14,7 +14,7 @@ * 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.view.error; +package com.hyperwallet.android.common.view.error; import static com.hyperwallet.android.ExceptionMapper.EC_AUTHENTICATION_TOKEN_PROVIDER_EXCEPTION; import static com.hyperwallet.android.ExceptionMapper.EC_IO_EXCEPTION; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/error/OnNetworkErrorCallback.java b/common/src/main/java/com/hyperwallet/android/common/view/error/OnNetworkErrorCallback.java similarity index 79% rename from ui/src/main/java/com/hyperwallet/android/ui/view/error/OnNetworkErrorCallback.java rename to common/src/main/java/com/hyperwallet/android/common/view/error/OnNetworkErrorCallback.java index c08b2e9bd..a6822c545 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/error/OnNetworkErrorCallback.java +++ b/common/src/main/java/com/hyperwallet/android/common/view/error/OnNetworkErrorCallback.java @@ -1,13 +1,13 @@ -package com.hyperwallet.android.ui.view.error; +package com.hyperwallet.android.common.view.error; import java.util.List; /** * Retry callback @see {@link DefaultErrorDialogFragment#newInstance(List)} - * */ + */ public interface OnNetworkErrorCallback { /** * Gets invoked when Error occurred and its possible to retry operation - * */ + */ void retry(); } diff --git a/ui/src/main/res/drawable/circle.xml b/common/src/main/res/drawable/circle.xml similarity index 100% rename from ui/src/main/res/drawable/circle.xml rename to common/src/main/res/drawable/circle.xml diff --git a/ui/src/main/res/drawable/circle_white.xml b/common/src/main/res/drawable/circle_white.xml similarity index 100% rename from ui/src/main/res/drawable/circle_white.xml rename to common/src/main/res/drawable/circle_white.xml diff --git a/ui/src/main/res/drawable/content_border_bottom.xml b/common/src/main/res/drawable/content_border_bottom.xml similarity index 100% rename from ui/src/main/res/drawable/content_border_bottom.xml rename to common/src/main/res/drawable/content_border_bottom.xml diff --git a/ui/src/main/res/drawable/content_border_top_bottom.xml b/common/src/main/res/drawable/content_border_top_bottom.xml similarity index 100% rename from ui/src/main/res/drawable/content_border_top_bottom.xml rename to common/src/main/res/drawable/content_border_top_bottom.xml diff --git a/ui/src/main/res/drawable/horizontal_divider.xml b/common/src/main/res/drawable/horizontal_divider.xml similarity index 100% rename from ui/src/main/res/drawable/horizontal_divider.xml rename to common/src/main/res/drawable/horizontal_divider.xml diff --git a/ui/src/main/res/drawable/ic_baseline_bug_report_24px.xml b/common/src/main/res/drawable/ic_baseline_bug_report_24px.xml similarity index 100% rename from ui/src/main/res/drawable/ic_baseline_bug_report_24px.xml rename to common/src/main/res/drawable/ic_baseline_bug_report_24px.xml diff --git a/ui/src/main/res/drawable/ic_baseline_cloud_off_24px.xml b/common/src/main/res/drawable/ic_baseline_cloud_off_24px.xml similarity index 100% rename from ui/src/main/res/drawable/ic_baseline_cloud_off_24px.xml rename to common/src/main/res/drawable/ic_baseline_cloud_off_24px.xml diff --git a/ui/src/main/res/drawable/ic_baseline_warning_24px.xml b/common/src/main/res/drawable/ic_baseline_warning_24px.xml similarity index 100% rename from ui/src/main/res/drawable/ic_baseline_warning_24px.xml rename to common/src/main/res/drawable/ic_baseline_warning_24px.xml diff --git a/ui/src/main/res/drawable/ic_check_14dp.xml b/common/src/main/res/drawable/ic_check_14dp.xml similarity index 100% rename from ui/src/main/res/drawable/ic_check_14dp.xml rename to common/src/main/res/drawable/ic_check_14dp.xml diff --git a/ui/src/main/res/drawable/ic_close_14dp.xml b/common/src/main/res/drawable/ic_close_14dp.xml similarity index 100% rename from ui/src/main/res/drawable/ic_close_14dp.xml rename to common/src/main/res/drawable/ic_close_14dp.xml diff --git a/ui/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml b/common/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml similarity index 100% rename from ui/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml rename to common/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml diff --git a/ui/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml b/common/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml similarity index 100% rename from ui/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml rename to common/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml diff --git a/ui/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml b/common/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml similarity index 100% rename from ui/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml rename to common/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml diff --git a/ui/src/main/res/drawable/ic_launcher_background.xml b/common/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from ui/src/main/res/drawable/ic_launcher_background.xml rename to common/src/main/res/drawable/ic_launcher_background.xml diff --git a/ui/src/main/res/drawable/ic_placeholder_24dp.xml b/common/src/main/res/drawable/ic_placeholder_24dp.xml similarity index 100% rename from ui/src/main/res/drawable/ic_placeholder_24dp.xml rename to common/src/main/res/drawable/ic_placeholder_24dp.xml diff --git a/ui/src/main/res/drawable/ic_search_24dp.xml b/common/src/main/res/drawable/ic_search_24dp.xml similarity index 100% rename from ui/src/main/res/drawable/ic_search_24dp.xml rename to common/src/main/res/drawable/ic_search_24dp.xml diff --git a/ui/src/main/res/drawable/ic_three_dots_16dp.xml b/common/src/main/res/drawable/ic_three_dots_16dp.xml similarity index 100% rename from ui/src/main/res/drawable/ic_three_dots_16dp.xml rename to common/src/main/res/drawable/ic_three_dots_16dp.xml diff --git a/ui/src/main/res/drawable/ic_trash.xml b/common/src/main/res/drawable/ic_trash.xml similarity index 100% rename from ui/src/main/res/drawable/ic_trash.xml rename to common/src/main/res/drawable/ic_trash.xml diff --git a/ui/src/main/res/drawable/oval.xml b/common/src/main/res/drawable/oval.xml similarity index 100% rename from ui/src/main/res/drawable/oval.xml rename to common/src/main/res/drawable/oval.xml diff --git a/ui/src/main/res/drawable/view_border_top_bottom.xml b/common/src/main/res/drawable/view_border_top_bottom.xml similarity index 100% rename from ui/src/main/res/drawable/view_border_top_bottom.xml rename to common/src/main/res/drawable/view_border_top_bottom.xml diff --git a/ui/src/main/res/font/icomoon.ttf b/common/src/main/res/font/icomoon.ttf old mode 100755 new mode 100644 similarity index 100% rename from ui/src/main/res/font/icomoon.ttf rename to common/src/main/res/font/icomoon.ttf diff --git a/ui/src/main/res/values/colors.xml b/common/src/main/res/values/colors.xml similarity index 100% rename from ui/src/main/res/values/colors.xml rename to common/src/main/res/values/colors.xml diff --git a/ui/src/main/res/values/dimens.xml b/common/src/main/res/values/dimens.xml similarity index 100% rename from ui/src/main/res/values/dimens.xml rename to common/src/main/res/values/dimens.xml diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml new file mode 100644 index 000000000..f46ffb1a3 --- /dev/null +++ b/common/src/main/res/values/strings.xml @@ -0,0 +1,9 @@ + + Error + Connectivity Issue + Unexpected Error + Cancel + Close + Try again + + diff --git a/common/src/main/res/values/styles.xml b/common/src/main/res/values/styles.xml new file mode 100644 index 000000000..8221087b3 --- /dev/null +++ b/common/src/main/res/values/styles.xml @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/src/test/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragmentPresenterTest.java b/common/src/test/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenterTest.java similarity index 92% rename from ui/src/test/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragmentPresenterTest.java rename to common/src/test/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenterTest.java index 05ff4966d..aa3848d07 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/view/error/DefaultErrorDialogFragmentPresenterTest.java +++ b/common/src/test/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenterTest.java @@ -1,8 +1,7 @@ -package com.hyperwallet.android.ui.view.error; +package com.hyperwallet.android.common.view.error; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -16,11 +15,12 @@ import android.content.res.Resources; -import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.common.R; import com.hyperwallet.android.model.HyperwalletError; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; import java.util.ArrayList; import java.util.Arrays; @@ -65,7 +65,7 @@ public void testBuildDialogMessage_buildDefaultExceptionMessage() { errors.add(new HyperwalletError("My default message", "my error code")); String message = presenter.buildDialogMessage(errors, resources); - verify(resources, never()).getString(anyInt()); + verify(resources, never()).getString(ArgumentMatchers.anyInt()); assertThat(message, is("My default message")); } diff --git a/receipt/.gitignore b/receipt/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/receipt/.gitignore @@ -0,0 +1 @@ +/build diff --git a/receipt/build.gradle b/receipt/build.gradle new file mode 100644 index 000000000..39c963b04 --- /dev/null +++ b/receipt/build.gradle @@ -0,0 +1,95 @@ +apply from: "$rootProject.projectDir/android-library.gradle" + +dependencies { + api project(":common") +} + +def aarFile = file("$buildDir/outputs/aar/receipt-$version" + ".aar") +def aarArtifact = artifacts.add('archives', aarFile) { + type 'aar' +} + +def isReleaseVersion = !version.endsWith('SNAPSHOT') + +publishing { + + repositories { + maven { + def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2" + def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots" + url = isReleaseVersion ? releasesRepoUrl : snapshotsRepoUrl + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + + publications { + hyperwalletReceiptUi(MavenPublication) { + groupId = hyperwalletGroupId + artifactId = 'receipt' + version = version + + artifact(sourcesJar) + artifact(javadocsJar) + artifact(aarArtifact) + + pom { + name = 'Hyperwallet Android Receipt UI SDK' + description = 'Hyperwallet Receipt UI SDK for Android to integrate with Hyperwallet Platform' + url = 'https://github.com/hyperwallet/hyperwallet-android-ui-sdk' + pom.withXml { + def dependenciesNode = asNode().appendNode('dependencies') + configurations.implementation.allDependencies.each { + def dependencyNode = dependenciesNode.appendNode('dependency') + if (it.group == "hyperwallet-android-ui-sdk") { + dependencyNode.appendNode('groupId', "com.hyperwallet.android") + } else { + dependencyNode.appendNode('groupId', it.group) + } + dependencyNode.appendNode('artifactId', it.name) + dependencyNode.appendNode('version', it.version) + } + } + licenses { + license { + name = 'MIT License' + url = 'http://www.opensource.org/licenses/MIT' + } + } + developers { + developer { + id = 'devs' + name = 'Hyperwallet Developers' + } + } + scm { + connection = 'scm:git:git://github.com/hyperwallet/hyperwallet-android-ui-sdk.git' + developerConnection = 'scm:git:git://github.com/hyperwallet/hyperwallet-android-ui-sdk.git' + url = 'https://github.com/hyperwallet/hyperwallet-android-ui-sdk' + } + } + } + } +} + +tasks.withType(Sign) { + onlyIf { + isReleaseVersion && sonatypeUsername?.trim() && sonatypePassword?.trim() + } +} + +signing { + sign publishing.publications.hyperwalletReceiptUi +} + +sonarqube { + properties { + def libraries = project.android.sdkDirectory.getPath() + "/platforms/android-28/android.jar" + property "sonar.sources", "src/main/java" + property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android" + property "sonar.libraries", libraries + property "sonar.projectName", "android-ui-sdk-receipt" + } +} \ No newline at end of file diff --git a/receipt/config/jacoco-settings.gradle b/receipt/config/jacoco-settings.gradle new file mode 100644 index 000000000..7ce61b7aa --- /dev/null +++ b/receipt/config/jacoco-settings.gradle @@ -0,0 +1,79 @@ +apply plugin: 'jacoco' + +final def jacocoVersion = "0.8.2" + +jacoco { + toolVersion = jacocoVersion +} + +android { + testOptions { + unitTests { + includeAndroidResources = true + returnDefaultValues = true + } + unitTests.all { + jacoco { + includeNoLocationClasses = true + } + } + } +} + +def fileFilter = ['**/BuildConfig.*'] + +def debugClassPaths = [ + '**/intermediates/javac/dev/*/classes/**' +] + +final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] + +task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { + + group = 'Reporting' + description = 'Generate Jacoco coverage reports.' + + reports { + html { + enabled = true + destination file("$buildDir/reports/jacoco") + } + } + + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${buildDir}/jacoco/testDevUnitTest.exec") +} + +task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { + + group = 'Verification' + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") + + violationRules { + setFailOnViolation(true) + + rule { + element = 'CLASS' + limit { + value = 'COVEREDRATIO' + counter = 'BRANCH' + minimum = 0.65 + } + } + } +} + diff --git a/receipt/config/lint.xml b/receipt/config/lint.xml new file mode 100644 index 000000000..3c83d4bb5 --- /dev/null +++ b/receipt/config/lint.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/receipt/proguard-rules.pro b/receipt/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/receipt/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/receipt/src/main/AndroidManifest.xml b/receipt/src/main/AndroidManifest.xml new file mode 100644 index 000000000..bf6f4ad0c --- /dev/null +++ b/receipt/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/receipt/src/main/res/values/strings.xml b/receipt/src/main/res/values/strings.xml new file mode 100644 index 000000000..c3ca11b97 --- /dev/null +++ b/receipt/src/main/res/values/strings.xml @@ -0,0 +1,103 @@ + + receipt + + Annual Fee + Annual Fee Refund + Customer Service Fee + Customer Service Fee Refund + Expedited Shipping Fee + Generic Fee Refund + Monthly Fee + Monthly Fee Refund + Payment Expiry Fee + Payment Fee + Processing Fee + Standard Shipping Fee + Transfer Fee + + + Balance Adjustment + Foreign Exchange + Funds Deposit + Adjustment + Payment Expired + + + Bank Account Return Fee + Bank Account Return + Bank Account Return Fee + Bank Account + + + Card Activation Fee + Card Activation Fee Waiver + Card Fee + Card Load + Balance Inquiry Fee + Cash Advance + Disputed Charge Refund + Disputed Card Deposit + ATM Withdrawal + PREPAID_CARD_EXCHANGE_RATE_DIFFERENCE + + Card Unload + ATM Withdrawal + PIN Change Fee + Refund + Card Replacement Fee + Transaction + Reversed Transaction + Card Unload + Card Load + + + Donation + Donation Fee + Donation Return + + + Merchant Payment + Merchant Payment Fee + Merchant Payment Refund + Merchant Payment Return + + + MoneyGram Return + MoneyGram + + + Paper Check Fee + Paper Check Refund + Paper Check + + + Account Closure + Account Closure Fee + Funds Unloaded + Dormant User Account Fee + Dormant User Account Fee Refund + Payment + Payment Cancellation + Payment Reversal + Payment Reversal Fee + Payment Return + Transfer to Program + Transfer to User + + + Promo Cancellation + Issued Promo + Promo Purchase + Promo Refund + + + Western Union + Wire Transfer + Western Union Withdrawal + Wire Transfer Return + + + Wire Transfer + Wire Transfer Fee + Wire Transfer Return + diff --git a/settings.gradle b/settings.gradle index 4f16d512e..905f2e4e9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':ui' +include ':ui', ':common', ':receipt' diff --git a/ui/build.gradle b/ui/build.gradle index 7fdbb6b2d..7d74976ae 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -1,90 +1,28 @@ -apply plugin: 'com.android.library' -apply plugin: 'maven-publish' -apply plugin: 'signing' -apply plugin: 'org.sonarqube' -apply from: "$projectDir/config/jacoco-settings.gradle" - -android { - compileSdkVersion 28 - defaultConfig { - minSdkVersion 21 - targetSdkVersion 28 - versionCode 1 - versionName version - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - testInstrumentationRunnerArgument "listener", "com.squareup.leakcanary.FailTestOnLeakRunListener" - } - - sourceSets { - androidTest { - resources.srcDirs += ['src/test/resources'] - } - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - debug { - testCoverageEnabled true - } - } - - lintOptions { - abortOnError true - warningsAsErrors true - lintConfig file("config/lint.xml") - } - -} - +apply from: "$rootProject.projectDir/android-library.gradle" dependencies { - implementation "androidx.appcompat:appcompat:1.0.2" - implementation "com.google.android.material:material:1.0.0" - implementation "androidx.constraintlayout:constraintlayout:1.1.3" - implementation "androidx.test.espresso:espresso-idling-resource:3.2.0" - implementation "androidx.legacy:legacy-support-v4:1.0.0" - implementation "androidx.recyclerview:recyclerview:1.0.0" - - api "com.hyperwallet.android:core-sdk:1.0.0-beta03-SNAPSHOT" - - androidTestImplementation "androidx.test.ext:junit:1.1.1" - androidTestImplementation "androidx.test:runner:1.2.0" - androidTestImplementation "androidx.test:rules:1.2.0" - androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0" - androidTestImplementation "androidx.test.espresso:espresso-contrib:3.2.0" - androidTestImplementation "androidx.test.espresso:espresso-intents:3.2.0" - androidTestImplementation "com.squareup.okhttp3:mockwebserver:3.11.0" - androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:1.6.3" - androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:1.6.3" - - testImplementation group: 'org.mockito', name: 'mockito-core', version: "2.27.0" - testImplementation group: 'pl.pragmatists', name: 'JUnitParams', version: "1.1.1" - testImplementation "org.robolectric:robolectric:4.1" - testImplementation "com.squareup.okhttp3:mockwebserver:3.11.0" + implementation "androidx.appcompat:appcompat:$appcompatVersion" + implementation "androidx.constraintlayout:constraintlayout:$constraintlayoutVersion" + implementation "androidx.legacy:legacy-support-v4:$legacySupportV4Version" + implementation "androidx.recyclerview:recyclerview:$recycleViewVersion" -} + api project(":common") + api project(":receipt") -task javadocs(type: Javadoc) { - source = android.sourceSets.main.java.srcDirs - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - failOnError false -} + androidTestImplementation "androidx.test:rules:$testRulesVersion" + androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" + androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" + androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockServerVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanaryVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:$leakcanaryVersion" -task javadocsJar(type: Jar, dependsOn: javadocs) { - classifier = 'javadoc' - from javadocs.destinationDir + testImplementation "org.robolectric:robolectric:$robolectricVersion" + testImplementation "com.squareup.okhttp3:mockwebserver:$mockWebServerVersion" } -task sourcesJar(type: Jar) { - classifier = 'sources' - from android.sourceSets.main.java.srcDirs -} -def aarFile = file("$buildDir/outputs/aar/ui-$version"+".aar") +def aarFile = file("$buildDir/outputs/aar/ui-$version" + ".aar") def aarArtifact = artifacts.add('archives', aarFile) { type 'aar' } @@ -107,7 +45,7 @@ publishing { publications { hyperwalletUi(MavenPublication) { - groupId = 'com.hyperwallet.android' + groupId = hyperwalletGroupId artifactId = 'ui-sdk' version = version @@ -123,7 +61,11 @@ publishing { def dependenciesNode = asNode().appendNode('dependencies') configurations.implementation.allDependencies.each { def dependencyNode = dependenciesNode.appendNode('dependency') - dependencyNode.appendNode('groupId', it.group) + if (it.group == "hyperwallet-android-ui-sdk") { + dependencyNode.appendNode('groupId', "com.hyperwallet.android") + } else { + dependencyNode.appendNode('groupId', it.group) + } dependencyNode.appendNode('artifactId', it.name) dependencyNode.appendNode('version', it.version) } diff --git a/ui/config/lint.xml b/ui/config/lint.xml index 1238724e4..7f32fbd3d 100644 --- a/ui/config/lint.xml +++ b/ui/config/lint.xml @@ -6,6 +6,8 @@ + + diff --git a/ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java b/ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java index 0917a22b2..9f42f6128 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java @@ -14,6 +14,10 @@ public final class HyperwalletMockWebServer extends TestWatcher { private MockWebServer mServer; private int port; + public HyperwalletMockWebServer(int port) { + this.port = port; + } + @Override protected void starting(Description description) { super.starting(description); @@ -36,10 +40,6 @@ protected void finished(Description description) { } } - public HyperwalletMockWebServer(int port) { - this.port = port; - } - public HyperwalletMockResponse mockResponse() { return new Builder(mServer).build(); } diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java index 61cd031aa..f8751b9b6 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java @@ -21,7 +21,7 @@ import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; import static java.net.HttpURLConnection.HTTP_OK; -import static com.hyperwallet.android.ui.view.error.DefaultErrorDialogFragment.RESULT_ERROR; +import static com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment.RESULT_ERROR; import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; import android.app.Instrumentation; @@ -35,13 +35,13 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.common.util.EspressoIdlingResource; +import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; -import com.hyperwallet.android.ui.util.EspressoIdlingResource; -import com.hyperwallet.android.ui.view.error.DefaultErrorDialogFragment; import com.hyperwallet.android.util.TestAuthenticationProvider; import org.junit.After; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java index 75b62af11..5bd2e49dd 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java @@ -45,13 +45,13 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.common.util.EspressoIdlingResource; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; -import com.hyperwallet.android.ui.util.EspressoIdlingResource; import com.hyperwallet.android.util.RecyclerViewCountAssertion; import com.hyperwallet.android.util.TestAuthenticationProvider; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java index 3003b01b3..f3c15fa11 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java @@ -42,13 +42,13 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.common.util.EspressoIdlingResource; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; -import com.hyperwallet.android.ui.util.EspressoIdlingResource; import com.hyperwallet.android.util.TestAuthenticationProvider; import org.junit.After; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java index ee49a0163..ec88b9dd0 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java @@ -44,13 +44,13 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.common.util.EspressoIdlingResource; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; -import com.hyperwallet.android.ui.util.EspressoIdlingResource; import com.hyperwallet.android.util.TestAuthenticationProvider; import org.junit.After; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java index 346b77ac5..c644703cd 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java @@ -42,12 +42,12 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.common.util.EspressoIdlingResource; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.transfermethod.SelectTransferMethodActivity; -import com.hyperwallet.android.ui.util.EspressoIdlingResource; import com.hyperwallet.android.util.RecyclerViewCountAssertion; import com.hyperwallet.android.util.TestAuthenticationProvider; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java index 4c5759831..d2f6b9123 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java @@ -84,9 +84,9 @@ public Intent getIntentSelectTransferMethodActivity(@NonNull final Context conte * @param country The transfer method country code. ISO 3166-1 alpha-2 format. * @param currency The transfer method currency code. ISO 4217 format. * @param transferMethodType The type of transfer method. For a complete list of transfer methods, see {@link - * com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes} + * com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes} * @param profileType The type of the account holder profile. For a complete list of options, see - * {@link com.hyperwallet.android.model.HyperwalletUser.ProfileTypes} + * {@link com.hyperwallet.android.model.user.HyperwalletUser.ProfileTypes} * @return an Intent with the data necessary to launch the {@link AddTransferMethodActivity} */ public Intent getIntentAddTransferMethodActivity(@NonNull final Context context, @NonNull final String country, diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/RepositoryFactory.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/RepositoryFactory.java index ec2a3a935..8ae21ee6d 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/RepositoryFactory.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/RepositoryFactory.java @@ -46,6 +46,10 @@ public static synchronized RepositoryFactory getInstance() { return sInstance; } + public static void clearInstance() { + sInstance = null; + } + public TransferMethodConfigurationRepository getTransferMethodConfigurationRepository() { return mTransferMethodConfigurationRepository; } @@ -57,8 +61,4 @@ public TransferMethodRepository getTransferMethodRepository() { public UserRepository getUserRepository() { return mUserRepository; } - - public static void clearInstance() { - sInstance = null; - } } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java index 6a07b1c6c..4fe1861a4 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java @@ -33,6 +33,7 @@ import androidx.annotation.VisibleForTesting; import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.common.util.EspressoIdlingResource; import com.hyperwallet.android.exception.HyperwalletException; import com.hyperwallet.android.listener.HyperwalletListener; import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; @@ -40,7 +41,7 @@ import com.hyperwallet.android.model.graphql.keyed.HyperwalletTransferMethodType; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationFieldQuery; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationKeysQuery; -import com.hyperwallet.android.ui.util.EspressoIdlingResource; +import com.hyperwallet.android.common.util.EspressoIdlingResource; import java.util.HashMap; import java.util.Map; @@ -48,9 +49,9 @@ import java.util.Set; public class TransferMethodConfigurationRepositoryImpl implements TransferMethodConfigurationRepository { - private HyperwalletTransferMethodConfigurationKey mTransferMethodConfigurationKey; private final Handler mHandler; private final Map mFieldMap; + private HyperwalletTransferMethodConfigurationKey mTransferMethodConfigurationKey; TransferMethodConfigurationRepositoryImpl() { mHandler = new Handler(); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java index 2a17b4aba..7d6b77063 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java @@ -38,7 +38,6 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.model.transfermethod.PayPalAccount; - public class TransferMethodRepositoryImpl implements TransferMethodRepository { private Handler mHandler = new Handler(); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java index 26cc9154b..4dbd6eb55 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java @@ -28,12 +28,12 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.common.view.error.OnNetworkErrorCallback; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.ui.view.WidgetDateDialogFragment; import com.hyperwallet.android.ui.view.WidgetSelectionDialogFragment; -import com.hyperwallet.android.ui.view.error.DefaultErrorDialogFragment; -import com.hyperwallet.android.ui.view.error.OnNetworkErrorCallback; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java index daaeafd5a..9f3f37654 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java @@ -30,11 +30,11 @@ import androidx.fragment.app.FragmentTransaction; import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.common.view.error.OnNetworkErrorCallback; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; -import com.hyperwallet.android.ui.view.error.DefaultErrorDialogFragment; -import com.hyperwallet.android.ui.view.error.OnNetworkErrorCallback; import com.hyperwallet.android.ui.view.widget.OneClickListener; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodActivity.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodActivity.java index 5a8ff0e92..a0582988b 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodActivity.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodActivity.java @@ -31,12 +31,12 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.common.view.error.OnNetworkErrorCallback; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.ui.view.CountrySelectionDialogFragment; import com.hyperwallet.android.ui.view.CurrencySelectionDialogFragment; -import com.hyperwallet.android.ui.view.error.DefaultErrorDialogFragment; -import com.hyperwallet.android.ui.view.error.OnNetworkErrorCallback; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java index 193aefd14..aa4a9408f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java @@ -354,6 +354,11 @@ public void reloadCurrencySelection() { mPresenter.loadCurrencySelection(mSelectedCountryCode, mSelectedCurrencyCode); } + private String getCountryDisplay(@NonNull final String countryCode) { + Locale locale = new Locale.Builder().setRegion(countryCode).build(); + return locale.getDisplayName(); + } + public interface TransferMethodSelectionItemListener { void onTransferMethodSelected(TransferMethodSelectionItem transferMethodType); @@ -384,11 +389,6 @@ interface OnLoadCurrencySelectionNetworkErrorCallback { void showErrorsLoadCurrencySelection(@NonNull final List errors); } - private String getCountryDisplay(@NonNull final String countryCode) { - Locale locale = new Locale.Builder().setRegion(countryCode).build(); - return locale.getDisplayName(); - } - private static class TransferMethodTypesAdapter extends RecyclerView.Adapter { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java index 91c35c5e3..828697756 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java @@ -217,6 +217,10 @@ public void onView() { } } + public interface CountrySelectionItemClickListener { + void onCountryItemClicked(String countryCode); + } + private static class Adapter extends RecyclerView.Adapter implements Filterable { private TreeMap mCountryNameCodeFilteredMap; @@ -350,8 +354,4 @@ void recycle() { } } } - - public interface CountrySelectionItemClickListener { - void onCountryItemClicked(String countryCode); - } } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java index 52f6428e3..84e0ed3fc 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java @@ -233,6 +233,10 @@ public void hideSoftKey(@NonNull View focusedView) { inputMethodManager.hideSoftInputFromWindow(focusedView.getWindowToken(), 0); } + public interface CurrencySelectionItemClickListener { + void onCurrencyItemClicked(String currencyCode); + } + private static class Adapter extends RecyclerView.Adapter implements Filterable { private TreeMap mCurrencyNameCodeFilteredMap; @@ -367,8 +371,4 @@ void recycle() { } } } - - public interface CurrencySelectionItemClickListener { - void onCurrencyItemClicked(String currencyCode); - } } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java index 5dab1341b..42b98af70 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java @@ -232,6 +232,10 @@ public interface WidgetSelectionItemListener { void onWidgetSelectionItemClicked(@NonNull final String selectedValue, @NonNull final String fieldName); } + public interface WidgetSelectionItemType { + void onWidgetSelectionItemClicked(@NonNull String selectedValue); + } + private static class Adapter extends RecyclerView.Adapter implements Filterable { private final Fragment mFragment; @@ -370,8 +374,4 @@ void recycle() { } } } - - public interface WidgetSelectionItemType { - void onWidgetSelectionItemClicked(@NonNull String selectedValue); - } } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java index 63471a56a..8ae7dfacf 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java @@ -42,8 +42,8 @@ import com.hyperwallet.android.model.graphql.field.HyperwalletField; public class ExpiryDateWidget extends AbstractWidget { - private ViewGroup mContainer; private final ExpireDateUtil mExpireDateUtil; + private ViewGroup mContainer; private TextInputLayout mTextInputLayout; private String mValue; private String mMessageInvalidDateLength; diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml index 659d07697..0c983668d 100644 --- a/ui/src/main/res/values/strings.xml +++ b/ui/src/main/res/values/strings.xml @@ -7,7 +7,8 @@ Select Transfer Method - @string/title_activity_select_transfer_method + @string/title_activity_select_transfer_method + Country Currency @@ -26,9 +27,6 @@ Default Account Select account as default method MM/YY - Error - Connectivity Issue - Unexpected Error Transaction Fee: Processing Time: @@ -47,9 +45,6 @@ Remove account Remove - Cancel - Close - Try again Transfer Funds diff --git a/ui/src/main/res/values/styles.xml b/ui/src/main/res/values/styles.xml index 6d39a8667..e5448bfce 100644 --- a/ui/src/main/res/values/styles.xml +++ b/ui/src/main/res/values/styles.xml @@ -1,4 +1,4 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java index 651cf534c..6135c42b2 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java @@ -58,6 +58,12 @@ @RunWith(RobolectricTestRunner.class) public class TransferMethodRepositoryImplTest { + @Rule + public ExpectedException mThrown = ExpectedException.none(); + @Rule + public MockitoRule mMockito = MockitoJUnit.rule(); + @Spy + TransferMethodRepositoryImpl mTransferMethodRepository; @Mock private Hyperwallet mHyperwallet; @Mock @@ -78,12 +84,6 @@ public class TransferMethodRepositoryImplTest { private ArgumentCaptor mStatusTransitionArgumentCaptor; @Captor private ArgumentCaptor> mListTransferMethodCaptor; - @Rule - public ExpectedException mThrown = ExpectedException.none(); - @Rule - public MockitoRule mMockito = MockitoJUnit.rule(); - @Spy - TransferMethodRepositoryImpl mTransferMethodRepository; @Before public void setup() { diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java b/ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java index 42aff932e..d35c7fa3a 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java @@ -42,18 +42,18 @@ @RunWith(RobolectricTestRunner.class) public class UserRepositoryImplTest { - @Mock - private Hyperwallet mHyperwallet; + @Rule + public MockitoRule mMockito = MockitoJUnit.rule(); @Mock UserRepository.LoadUserCallback mMockCallback; + @Spy + UserRepositoryImpl mUserRepository; + @Mock + private Hyperwallet mHyperwallet; @Captor private ArgumentCaptor mErrorCaptor; @Captor private ArgumentCaptor mUserCaptor; - @Rule - public MockitoRule mMockito = MockitoJUnit.rule(); - @Spy - UserRepositoryImpl mUserRepository; @Before public void setup() { diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java index 695ea3d0a..623caad7b 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java @@ -57,8 +57,11 @@ public class AddTransferMethodPresenterTest { private final HyperwalletBankAccount bankAccount = new HyperwalletBankAccount .Builder("CA", "CAD", "3423423432") .build(); + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + @Rule + public HyperwalletExternalResourceManager externalResourceManager = new HyperwalletExternalResourceManager(); private AddTransferMethodPresenter presenter; - @Mock private TransferMethodConfigurationRepository tmcRepository; @Mock @@ -69,10 +72,6 @@ public class AddTransferMethodPresenterTest { private ArgumentCaptor> fieldArgumentCaptor; @Captor private ArgumentCaptor> mErrorListArgumentCaptor; - @Rule - public MockitoRule mockito = MockitoJUnit.rule(); - @Rule - public HyperwalletExternalResourceManager externalResourceManager = new HyperwalletExternalResourceManager(); @Before public void setUp() { diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java index b6e46f9f9..269efa42e 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java @@ -33,6 +33,8 @@ public class FeeFormatterTest { @Rule public MockitoRule mockito = MockitoJUnit.rule(); + @Rule + public HyperwalletExternalResourceManager externalResourceManager = new HyperwalletExternalResourceManager(); @Captor private ArgumentCaptor resourceIdCaptor; @Captor @@ -41,9 +43,6 @@ public class FeeFormatterTest { private Context context; @Mock private Resources resources; - @Rule - public HyperwalletExternalResourceManager externalResourceManager = new HyperwalletExternalResourceManager(); - private HyperwalletFee mFlatFee; private JSONObject mJSONObject; diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodPresenterTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodPresenterTest.java index aa674e769..b1d95f838 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodPresenterTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodPresenterTest.java @@ -57,6 +57,14 @@ public class ListTransferMethodPresenterTest { + private final HyperwalletErrors errors = createErrors(); + private final HyperwalletBankAccount bankAccount = new HyperwalletBankAccount + .Builder("CA", "CAD", "3423423432") + .build(); + private final HyperwalletStatusTransition statusTransition = + new HyperwalletStatusTransition(HyperwalletStatusTransition.StatusDefinition.DE_ACTIVATED); + @Rule + public MockitoRule mMockito = MockitoJUnit.rule(); @Mock private TransferMethodRepository mTransferMethodRepository; @Mock @@ -65,15 +73,6 @@ public class ListTransferMethodPresenterTest { private ArgumentCaptor> mListArgumentErrorCaptor; @Captor private ArgumentCaptor> mListArgumentTransferMethodCaptor; - @Rule - public MockitoRule mMockito = MockitoJUnit.rule(); - - private final HyperwalletErrors errors = createErrors(); - private final HyperwalletBankAccount bankAccount = new HyperwalletBankAccount - .Builder("CA", "CAD", "3423423432") - .build(); - private final HyperwalletStatusTransition statusTransition = - new HyperwalletStatusTransition(HyperwalletStatusTransition.StatusDefinition.DE_ACTIVATED); private ListTransferMethodPresenter presenter; @Before diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java index e58c7c6f2..9a109230a 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java @@ -41,19 +41,18 @@ @RunWith(RobolectricTestRunner.class) public class SelectTransferMethodPresenterTest { + private final HyperwalletErrors errors = createErrors(); + @Rule + public HyperwalletExternalResourceManager externalResourceManager = new HyperwalletExternalResourceManager(); @Mock private SelectTransferMethodContract.View view; @Mock private TransferMethodConfigurationRepositoryImpl mTransferMethodConfigurationRepository; @Mock private UserRepositoryImpl mUserRepository; - @Rule - public HyperwalletExternalResourceManager externalResourceManager = new HyperwalletExternalResourceManager(); - private HyperwalletTransferMethodConfigurationKey mResult; private HyperwalletUser mUser; private SelectTransferMethodPresenter selectTransferMethodPresenter; - private final HyperwalletErrors errors = createErrors(); @Before public void initialize() throws Exception { From c3c384b43c87f346287b9433a7c7f319246f38d7 Mon Sep 17 00:00:00 2001 From: Peter Joseph Olamit Date: Tue, 11 Jun 2019 14:44:59 -0700 Subject: [PATCH 013/177] HW-52584 receipt list (#31) --- build.gradle | 2 + .../android/common/util/DateUtils.java | 123 ++++++ .../view/HorizontalDividerItemDecorator.java | 8 +- .../android/common/viewmodel/Event.java | 65 +++ common/src/main/res/drawable/circle.xml | 2 +- common/src/main/res/drawable/circle_white.xml | 8 +- common/src/main/res/font/icomoon.ttf | Bin 21940 -> 21992 bytes common/src/main/res/values/colors.xml | 1 + common/src/main/res/values/dimens.xml | 2 + .../android/common/util/DateUtilsTest.java | 63 +++ receipt/build.gradle | 16 + receipt/src/androidTest/AndroidManifest.xml | 9 + ...yperwalletInstrumentedTestApplication.java | 31 ++ .../android/receipt/ListReceiptsTest.java | 265 ++++++++++++ .../HyperwalletExternalResourceManager.java | 73 ++++ .../rule/HyperwalletMockWebServer.java | 115 ++++++ .../android/util/EspressoUtils.java | 187 +++++++++ .../android/util/NestedScrollToAction.java | 41 ++ .../util/RecyclerViewCountAssertion.java | 30 ++ .../util/TestAuthenticationProvider.java | 51 +++ receipt/src/main/AndroidManifest.xml | 15 +- .../receipt/repository/ReceiptDataSource.java | 189 +++++++++ .../repository/ReceiptDataSourceFactory.java | 54 +++ .../receipt/repository/ReceiptRepository.java | 58 +++ .../repository/ReceiptRepositoryFactory.java | 56 +++ .../repository/ReceiptRepositoryImpl.java | 93 +++++ .../receipt/view/ListReceiptActivity.java | 133 ++++++ .../receipt/view/ListReceiptFragment.java | 264 ++++++++++++ .../view/ReceiptItemDividerDecorator.java | 102 +++++ .../viewmodel/ListReceiptViewModel.java | 93 +++++ .../src/main/res/drawable/circle_negative.xml | 9 + .../src/main/res/drawable/circle_positive.xml | 9 + .../main/res/drawable/item_view_border.xml | 20 + .../res/drawable/item_view_border_header.xml | 20 + .../main/res/layout/activity_list_receipt.xml | 41 ++ receipt/src/main/res/layout/item_receipt.xml | 73 ++++ .../res/layout/item_receipt_with_header.xml | 26 ++ .../main/res/layout/list_receipt_fragment.xml | 26 ++ receipt/src/main/res/values/colors.xml | 6 + receipt/src/main/res/values/dimens.xml | 6 + receipt/src/main/res/values/strings.xml | 15 + receipt/src/main/res/values/styles.xml | 19 + .../main/res/xml/network_security_config.xml | 6 + .../ReceiptDataSourceFactoryTest.java | 38 ++ .../repository/ReceiptDataSourceTest.java | 389 ++++++++++++++++++ .../ReceiptRepositoryFactoryTest.java | 39 ++ .../HyperwalletExternalResourceManager.java | 72 ++++ .../authentication_token_response.json | 3 + .../resources/receipt_credit_response.json | 30 ++ .../resources/receipt_debit_response.json | 25 ++ .../receipt_list_date_grouping_response.json | 90 ++++ .../test/resources/receipt_list_response.json | 64 +++ .../receipt_unknown_type_response.json | 30 ++ ui/src/androidTest/AndroidManifest.xml | 2 +- .../hyperwallet/android/ui/HyperwalletUi.java | 8 + .../TransferMethodRepositoryImpl.java | 8 +- .../ListTransferMethodFragment.java | 4 +- .../SelectTransferMethodFragment.java | 4 +- .../TransferMethodRepositoryImplTest.java | 8 +- 59 files changed, 3217 insertions(+), 22 deletions(-) create mode 100644 common/src/main/java/com/hyperwallet/android/common/util/DateUtils.java rename {ui/src/main/java/com/hyperwallet/android/ui => common/src/main/java/com/hyperwallet/android/common}/view/HorizontalDividerItemDecorator.java (96%) create mode 100644 common/src/main/java/com/hyperwallet/android/common/viewmodel/Event.java create mode 100644 common/src/test/java/com/hyperwallet/android/common/util/DateUtilsTest.java create mode 100644 receipt/src/androidTest/AndroidManifest.xml create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSource.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactory.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepository.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactory.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryImpl.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptActivity.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptFragment.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/receipt/view/ReceiptItemDividerDecorator.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/receipt/viewmodel/ListReceiptViewModel.java create mode 100644 receipt/src/main/res/drawable/circle_negative.xml create mode 100644 receipt/src/main/res/drawable/circle_positive.xml create mode 100644 receipt/src/main/res/drawable/item_view_border.xml create mode 100644 receipt/src/main/res/drawable/item_view_border_header.xml create mode 100644 receipt/src/main/res/layout/activity_list_receipt.xml create mode 100644 receipt/src/main/res/layout/item_receipt.xml create mode 100644 receipt/src/main/res/layout/item_receipt_with_header.xml create mode 100644 receipt/src/main/res/layout/list_receipt_fragment.xml create mode 100644 receipt/src/main/res/values/colors.xml create mode 100644 receipt/src/main/res/values/dimens.xml create mode 100644 receipt/src/main/res/values/styles.xml create mode 100644 receipt/src/main/res/xml/network_security_config.xml create mode 100644 receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactoryTest.java create mode 100644 receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceTest.java create mode 100644 receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactoryTest.java create mode 100644 receipt/src/test/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java create mode 100644 receipt/src/test/resources/authentication_token_response.json create mode 100644 receipt/src/test/resources/receipt_credit_response.json create mode 100644 receipt/src/test/resources/receipt_debit_response.json create mode 100644 receipt/src/test/resources/receipt_list_date_grouping_response.json create mode 100644 receipt/src/test/resources/receipt_list_response.json create mode 100644 receipt/src/test/resources/receipt_unknown_type_response.json diff --git a/build.gradle b/build.gradle index 3df2d26b2..4cfcc4791 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,8 @@ subprojects { constraintlayoutVersion = '1.1.3' legacySupportV4Version = '1.0.0' recycleViewVersion = '1.0.0' + lifecycleExtensionsVersion = '2.0.0' + pagingRuntimeVersion = '2.1.0' //Testing extJunitVerson = '1.1.1' testRunnerVersion = '1.2.0' diff --git a/common/src/main/java/com/hyperwallet/android/common/util/DateUtils.java b/common/src/main/java/com/hyperwallet/android/common/util/DateUtils.java new file mode 100644 index 000000000..7fd65e5aa --- /dev/null +++ b/common/src/main/java/com/hyperwallet/android/common/util/DateUtils.java @@ -0,0 +1,123 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.common.util; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/** + * Common HW-SDK UI Date Utility class, that will assist on safe presentation of date whatever the mobile device setting + * is set Locale, Timezone and etc... that dictates how that dates are being presented + * + * Moreover all date string to {@link Date} object conversion is automatically converted from + * GMT date string from API to locale Date set by the phone + */ +public final class DateUtils { + + private static final String DATE_FORMAT = "yyyy-MM-dd"; + private static final String DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; + private static final String DATE_TIME_FORMAT_MILLISECONDS = "yyyy-MM-dd'T'HH:mm:ss.SSS"; + private static final TimeZone API_TIMEZONE = TimeZone.getTimeZone("GMT"); + + private DateUtils() { + } + + /** + * Creates a string date format: yyyy-MM-dd + * + * @param date Date object + * @return string date in yyyy-MM-dd format + */ + public static String toDateFormat(@NonNull final Date date) { + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.getDefault()); + dateFormat.setTimeZone(TimeZone.getDefault()); + return dateFormat.format(date); + } + + /** + * Creates a string date in specified format + * + * @param date Date object + * @param format specify desired format of date + * @return formatted date string based on format specified + */ + public static String toDateFormat(@NonNull final Date date, @NonNull final String format) { + SimpleDateFormat dateFormat = new SimpleDateFormat(format, Locale.getDefault()); + dateFormat.setTimeZone(TimeZone.getDefault()); + return dateFormat.format(date); + } + + /** + * Creates a string date format + * + * @param date Date object + * @return formatted string in yyyy-MM-dd'T'HH:mm:ss format + */ + public static String toDateTimeFormat(@NonNull final Date date) { + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_TIME_FORMAT, Locale.getDefault()); + dateFormat.setTimeZone(TimeZone.getDefault()); + return dateFormat.format(date); + } + + /** + * Creates a string date format + * + * @param date Date object + * @return formatted string in yyyy-MM-dd'T'HH:mm:ss.SSS format + */ + public static String toDateTimeMillisFormat(@NonNull final Date date) { + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_TIME_FORMAT_MILLISECONDS, Locale.getDefault()); + dateFormat.setTimeZone(TimeZone.getDefault()); + return dateFormat.format(date); + } + + /** + * Creates a Date object from string date using API Timezone + * + * @param dateString String date from API with GMT timezone + * @return date Date object converted to local timezone + * @throws IllegalArgumentException when string is un-parsable + */ + public static Date fromDateTimeString(@NonNull final String dateString) { + try { + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_TIME_FORMAT, Locale.getDefault()); + dateFormat.setTimeZone(API_TIMEZONE); + return dateFormat.parse(dateString); + } catch (ParseException e) { + throw new IllegalArgumentException("An exception occurred when attempting to parse " + + "the date " + dateString, e); + } + } + + @VisibleForTesting + static Date fromDateTimeString(@NonNull final String dateString, @NonNull final String format) { + try { + SimpleDateFormat dateFormat = new SimpleDateFormat(format, Locale.getDefault()); + dateFormat.setTimeZone(API_TIMEZONE); + return dateFormat.parse(dateString); + } catch (ParseException e) { + throw new IllegalArgumentException("An exception occurred when attempting to parse " + + "the date " + dateString, e); + } + } +} diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/HorizontalDividerItemDecorator.java b/common/src/main/java/com/hyperwallet/android/common/view/HorizontalDividerItemDecorator.java similarity index 96% rename from ui/src/main/java/com/hyperwallet/android/ui/view/HorizontalDividerItemDecorator.java rename to common/src/main/java/com/hyperwallet/android/common/view/HorizontalDividerItemDecorator.java index 22b3b432a..3e9d3777f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/HorizontalDividerItemDecorator.java +++ b/common/src/main/java/com/hyperwallet/android/common/view/HorizontalDividerItemDecorator.java @@ -14,7 +14,7 @@ * 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.view; +package com.hyperwallet.android.common.view; import android.content.Context; import android.graphics.Canvas; @@ -26,12 +26,12 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; -import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.common.R; public class HorizontalDividerItemDecorator extends RecyclerView.ItemDecoration { - private final Drawable mHorizontalItemDivider; - private final int mDefaultPadding; + protected final Drawable mHorizontalItemDivider; + protected final int mDefaultPadding; public HorizontalDividerItemDecorator(@NonNull final Context context, final boolean withHeaderDivider) { mHorizontalItemDivider = context.getResources().getDrawable(R.drawable.horizontal_divider, null); diff --git a/common/src/main/java/com/hyperwallet/android/common/viewmodel/Event.java b/common/src/main/java/com/hyperwallet/android/common/viewmodel/Event.java new file mode 100644 index 000000000..a07aab0e1 --- /dev/null +++ b/common/src/main/java/com/hyperwallet/android/common/viewmodel/Event.java @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.common.viewmodel; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * Class that represents {@link androidx.lifecycle.LiveData} event with content + */ +public class Event { + + private final T content; + private boolean mIsContentConsumed; + + public Event(@NonNull final T t) { + content = t; + } + + /** + * @return content of this event, will also mark {@link Event#mIsContentConsumed} to true + * that will also mean that {@link Event#getContentIfNotConsumed()} will also return true + */ + @NonNull + public T getContent() { + mIsContentConsumed = true; + return content; + } + + /** + * @return true if content assigned to event is already referenced + * from {@link Event#getContent()}; false otherwise. + */ + public boolean isContentConsumed() { + return mIsContentConsumed; + } + + /** + * Retrieve assigned content based on if and only if content has not been referenced from {@link Event#getContent()} + * + * @return content if content is not yet consumed; otherwise null + */ + @Nullable + public T getContentIfNotConsumed() { + if (!mIsContentConsumed) { + mIsContentConsumed = true; + return content; + } + return null; + } +} diff --git a/common/src/main/res/drawable/circle.xml b/common/src/main/res/drawable/circle.xml index b6e02a0bc..4a83f9077 100644 --- a/common/src/main/res/drawable/circle.xml +++ b/common/src/main/res/drawable/circle.xml @@ -3,7 +3,7 @@ - + diff --git a/common/src/main/res/drawable/circle_white.xml b/common/src/main/res/drawable/circle_white.xml index 237aac74a..def791761 100644 --- a/common/src/main/res/drawable/circle_white.xml +++ b/common/src/main/res/drawable/circle_white.xml @@ -4,11 +4,9 @@ - - - - - + + diff --git a/common/src/main/res/font/icomoon.ttf b/common/src/main/res/font/icomoon.ttf index f216ee945686dacd9a87036c7df1f9b6e34b6fa0..384737f83301b709956e43431d06b3b965b73c2f 100644 GIT binary patch delta 990 zcma)4TWk|Y6rDS>4{!Wf+w1k#d04hLFG6U7qxGtZ6GHQ0ND8s+qz@1(ZlI22r=$sL z)2OXe6!DM{Rk4hUh=c$kAw_Bn;Ugb>1Ox~ng!<8s!WU9$1yNNAsii7Sx4rB1r+*#Y z(abq#=G?n?_Ua-$S%eY+LWq;h5k@+PvmJ5SFSH|b4d>pmiQMGxzg)RX2-G9qm(NX4 z;_5{_hpQuB{OH~8p1pCzM+r%b%T4S*Jt+N&xF3@oo;)yp5DUdI zdgqJf6ws3}40I_CAIf4s2yBJUmhXEbIa3V?daSt@bQXrLc%m1gy3#eP4F%wAU6@8I zvB+mT7xdVI=<(i>T~1#l6&PsG>{_d+J5@SsRiN+#4y&@d+9bEtKU>ulMO(ElEB>vo zKC>!>Tp0E>mePN(u&>w(*+7QKCs&630ADDd1 zrq^R5*kU4%R}&^`7$|8t1Bvq;baN&f{60Q8sFGFeEM)7dV`{=|Cw zba_6zqhq1=*SbTIhtYRpeX(!#FZJ7vGfm$#A8t9+a;f#r)=#T>46cxbj HBNyQx%+A&M delta 928 zcmZ`&OK1~87@o;yXLpk}n`EkL`d@TN(2;#wEcK-Rk`Ty_#7G~bx zzza9<6v7B0JDNrmigu)GW4xPG19JzyeSJge(XStGJwXVU0q!42kBvff0-lD*4h$YS z@Vf5GTfip~>Riq2PxpH+Y@A1^Yd4(7Ge9s8sZW4s0f#a}M>ZzXV72#_v z?_P5i+Xc0)WJhgp`e&=RyTmeMOyHTXFpLSqsB%SQObp56kql#26p~3m6PG$%p{Z8H zQj63i>PBA^BJDwCU82GM>k{TzI3DI4 zw3VWKzDA$V>K8+youN?W7GGJ+Ey#A8Ez#gtl=etO4=^s4<1B-sz#i3*+D@r{Y#2lnF~&+th%Bap_>)&!*?r}st)GgpKh%}f~kZo+2=h%uBH1j{tdXc BxZwZ* diff --git a/common/src/main/res/values/colors.xml b/common/src/main/res/values/colors.xml index 2d8989b26..39fdb8129 100644 --- a/common/src/main/res/values/colors.xml +++ b/common/src/main/res/values/colors.xml @@ -23,5 +23,6 @@ #E5F7FA + #737373 diff --git a/common/src/main/res/values/dimens.xml b/common/src/main/res/values/dimens.xml index 1a3f3fb32..db66a3e95 100644 --- a/common/src/main/res/values/dimens.xml +++ b/common/src/main/res/values/dimens.xml @@ -73,4 +73,6 @@ 4dp 6dp 32dp + 48dp + 3dp diff --git a/common/src/test/java/com/hyperwallet/android/common/util/DateUtilsTest.java b/common/src/test/java/com/hyperwallet/android/common/util/DateUtilsTest.java new file mode 100644 index 000000000..27102325b --- /dev/null +++ b/common/src/test/java/com/hyperwallet/android/common/util/DateUtilsTest.java @@ -0,0 +1,63 @@ +package com.hyperwallet.android.common.util; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Date; +import java.util.TimeZone; + +public class DateUtilsTest { + + @Before + public void setTestLocalTimezone() { + TimeZone.setDefault(TimeZone.getTimeZone("PST")); + } + + @Test + public void testToDateFormat_returnsExpectedStringFormat() { + String dateString = "2019-05-27"; + Date dateTarget = DateUtils.fromDateTimeString("2019-05-27T15:57:49"); + + // test + String targetDate = DateUtils.toDateFormat(dateTarget); + assertThat(targetDate, is(notNullValue())); + assertThat(targetDate, is(dateString)); + } + + @Test + public void testToDateFormat_returnsExpectedStringFormatFromParameter() { + String dateString = "November 2019"; + Date dateTarget = DateUtils.fromDateTimeString("2019-11-27T15:57:49"); + + // test + String targetDate = DateUtils.toDateFormat(dateTarget, "MMMM yyyy"); + assertThat(targetDate, is(notNullValue())); + assertThat(targetDate, is(dateString)); + } + + @Test + public void testToDateTimeFormat_returnsExpectedStringFormat() { + String localTime = "2019-11-27T07:57:00"; + Date dateTarget = DateUtils.fromDateTimeString("2019-11-27T15:57:00"); + + // test + String targetDate = DateUtils.toDateTimeFormat(dateTarget); + assertThat(targetDate, is(notNullValue())); + assertThat(targetDate, is(localTime)); + } + + @Test + public void testToDateTimeMillisFormat_returnsExpectedStringFormat() { + String localTime = "2019-11-27T07:57:00.000"; + Date dateTarget = DateUtils.fromDateTimeString("2019-11-27T15:57:00.000", "yyyy-MM-dd'T'HH:mm:ss.SSS"); + + // test + String targetDate = DateUtils.toDateTimeMillisFormat(dateTarget); + assertThat(targetDate, is(notNullValue())); + assertThat(targetDate, is(localTime)); + } +} diff --git a/receipt/build.gradle b/receipt/build.gradle index 39c963b04..6aa8d9d42 100644 --- a/receipt/build.gradle +++ b/receipt/build.gradle @@ -2,6 +2,22 @@ apply from: "$rootProject.projectDir/android-library.gradle" dependencies { api project(":common") + + implementation "com.google.android.material:material:$androidMaterialVersion" + implementation "androidx.constraintlayout:constraintlayout:$constraintlayoutVersion" + implementation "androidx.legacy:legacy-support-v4:$legacySupportV4Version" + implementation "androidx.recyclerview:recyclerview:$recycleViewVersion" + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion" + implementation "androidx.paging:paging-runtime:$pagingRuntimeVersion" + + testImplementation "org.robolectric:robolectric:$robolectricVersion" + + androidTestImplementation "androidx.test:rules:$testRulesVersion" + androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" + androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" + androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockServerVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanaryVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:$leakcanaryVersion" } def aarFile = file("$buildDir/outputs/aar/receipt-$version" + ".aar") diff --git a/receipt/src/androidTest/AndroidManifest.xml b/receipt/src/androidTest/AndroidManifest.xml new file mode 100644 index 000000000..8495adb45 --- /dev/null +++ b/receipt/src/androidTest/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java b/receipt/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java new file mode 100644 index 000000000..dfc559d2e --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java @@ -0,0 +1,31 @@ +package com.hyperwallet.android; + + +import android.app.Application; + +import com.squareup.leakcanary.InstrumentationLeakDetector; +import com.squareup.leakcanary.LeakCanary; + +public class HyperwalletInstrumentedTestApplication extends Application { + + @Override + public void onCreate() { + + super.onCreate(); + if (LeakCanary.isInAnalyzerProcess(this)) { + // This process is dedicated to LeakCanary for heap analysis. + // You should not init your app in this process. + return; + } + installLeakCanary(); + } + + + protected void installLeakCanary() { + + InstrumentationLeakDetector.instrumentationRefWatcher(this) + .buildAndInstall(); + + } + +} \ No newline at end of file diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java b/receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java new file mode 100644 index 000000000..5eb430354 --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java @@ -0,0 +1,265 @@ +package com.hyperwallet.android.receipt; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +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 org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.instanceOf; + +import static java.net.HttpURLConnection.HTTP_NO_CONTENT; +import static java.net.HttpURLConnection.HTTP_OK; + +import static com.hyperwallet.android.util.EspressoUtils.atPosition; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.widget.TextView; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.rule.ActivityTestRule; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.receipt.repository.ReceiptRepositoryFactory; +import com.hyperwallet.android.receipt.view.ListReceiptActivity; +import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.util.RecyclerViewCountAssertion; +import com.hyperwallet.android.util.TestAuthenticationProvider; + +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.util.Locale; + +@RunWith(AndroidJUnit4.class) +public class ListReceiptsTest { + + @ClassRule + public static HyperwalletExternalResourceManager sResourceManager = new HyperwalletExternalResourceManager(); + @Rule + public HyperwalletMockWebServer mMockWebServer = new HyperwalletMockWebServer(8080); + @Rule + public ActivityTestRule mActivityTestRule = + new ActivityTestRule<>(ListReceiptActivity.class, true, false); + + @Before + public void setup() { + Hyperwallet.getInstance(new TestAuthenticationProvider()); + + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("authentication_token_response.json")).mock(); + + setLocale(Locale.US); + } + + @After + public void cleanup() { + ReceiptRepositoryFactory.clearInstance(); + } + + @Test + public void testListReceipts_userHasMultipleTransactions() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_list_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.receipt.R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("Payment"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("+ 20.00"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("June 07, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(matches(atPosition(1, + hasDescendant(withText(com.hyperwallet.android.receipt.R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(1, hasDescendant(withText("Payment"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(1, hasDescendant(withText("+ 25.00"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(1, hasDescendant(withText("June 02, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(1, hasDescendant(withText("CAD"))))); + + onView(withId(R.id.list_receipts)).check(matches(atPosition(2, + hasDescendant(withText(com.hyperwallet.android.receipt.R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(2, hasDescendant(withText("Card Activation Fee"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(2, hasDescendant(withText("- 1.95"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(2, hasDescendant(withText("June 01, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(2, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(3, hasDescendant(withText("December 2018"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(3, + hasDescendant(withText(com.hyperwallet.android.receipt.R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(3, hasDescendant(withText("Card Load"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(3, hasDescendant(withText("- 18.05"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(3, hasDescendant(withText("December 01, 2018"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(3, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(4)); + } + + @Test + public void testListReceipts_displayCreditTransaction() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_credit_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.receipt.R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.payment))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("+ 25.00"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("June 02, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("CAD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); + } + + @Test + public void testListReceipts_displayDebitTransaction() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_debit_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("May 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.receipt.R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.transfer_to_prepaid_card))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("- 18.05"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("May 02, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); + } + + @Test + public void testListReceipts_displayUnknownTransactionType() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_unknown_type_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.receipt.R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.unknown_type))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("+ 25.00"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("June 02, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("CAD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); + } + + @Test + public void testListReceipt_userHasNoTransactions() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.toolbar)).check(matches(isDisplayed())); + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + //todo: check empty view when it will be ready + } + + @Test + public void testListReceipts_checkDateTextOnLocaleChange() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_debit_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + setLocale(Locale.ITALY); + // run test + mActivityTestRule.launchActivity(null); + // assert + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("maggio 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("maggio 02, 2019"))))); + mActivityTestRule.finishActivity(); + setLocale(Locale.US); + mActivityTestRule.launchActivity(null); + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("May 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("May 02, 2019"))))); + } + + private void setLocale(Locale locale) { + Context context = ApplicationProvider.getApplicationContext(); + Locale.setDefault(locale); + Resources resources = context.getResources(); + Configuration configuration = resources.getConfiguration(); + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.JELLY_BEAN) { + configuration.setLocale(locale); + } else { + configuration.locale = locale; + } + resources.updateConfiguration(configuration, resources.getDisplayMetrics()); + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java b/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java new file mode 100644 index 000000000..e7e546063 --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java @@ -0,0 +1,73 @@ +package com.hyperwallet.android.rule; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class HyperwalletExternalResourceManager extends TestWatcher { + + private static final String EMPTY = ""; + private ClassLoader classLoader; + private Logger logger; + + @Override + protected void starting(Description description) { + super.starting(description); + classLoader = description.getTestClass().getClassLoader(); + logger = Logger.getLogger(description.getTestClass().getName()); + } + + public String getResourceContent(final String resourceName) { + if (resourceName == null) { + throw new IllegalArgumentException("Parameter resourceName cannot be null"); + } + + return getContent(resourceName); + } + + private String getContent(final String resourceName) { + + URL resource = classLoader.getResource(resourceName); + InputStream inputStream = null; + Writer writer = new StringWriter(); + String resourceContent = EMPTY; + if (resource != null) { + try { + inputStream = resource.openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + String line = reader.readLine(); + while (line != null) { + writer.write(line); + line = reader.readLine(); + } + resourceContent = writer.toString(); + + } catch (Exception e) { + logger.log(Level.WARNING, "There was an error loading an external resource", e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "There was an error closing input stream", e); + } + try { + writer.close(); + } catch (IOException e) { + logger.log(Level.SEVERE, "There was an error closing writer", e); + } + } + } + return resourceContent; + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java b/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java new file mode 100644 index 000000000..9f42f6128 --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java @@ -0,0 +1,115 @@ +package com.hyperwallet.android.rule; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +import java.io.IOException; +import java.net.HttpURLConnection; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +public final class HyperwalletMockWebServer extends TestWatcher { + + private MockWebServer mServer; + private int port; + + public HyperwalletMockWebServer(int port) { + this.port = port; + } + + @Override + protected void starting(Description description) { + super.starting(description); + mServer = new MockWebServer(); + try { + mServer.start(port); + } catch (IOException e) { + throw new IllegalStateException("Unable to start mock server", e); + } + } + + @Override + protected void finished(Description description) { + super.finished(description); + try { + mServer.shutdown(); + mServer.close(); + } catch (IOException e) { + throw new IllegalStateException("Un error occurred when shutting down mock server", e); + } + } + + public HyperwalletMockResponse mockResponse() { + return new Builder(mServer).build(); + } + + public MockWebServer getServer() { + return mServer; + } + + public static class HyperwalletMockResponse { + + private String path; + private String body; + private int httpResponseCode; + private Builder builder; + + HyperwalletMockResponse(Builder builder) { + this.path = builder.path; + this.httpResponseCode = builder.responseCode; + this.body = builder.body; + this.builder = builder; + } + + public HyperwalletMockResponse withHttpResponseCode(final int code) { + builder.responseCode(code); + return builder.build(); + } + + public HyperwalletMockResponse withBody(final String body) { + builder.body(body); + return builder.build(); + } + + public void mock() { + mockRequest(); + } + + private String mockRequest() { + builder.server.enqueue(new MockResponse().setResponseCode(httpResponseCode).setBody(body)); + return builder.server.url(path).toString(); + } + + } + + private static class Builder { + + private String path; + private String body; + private int responseCode; + private MockWebServer server; + + + Builder(final MockWebServer server) { + this.path = ""; + this.responseCode = HttpURLConnection.HTTP_OK; + this.body = ""; + this.server = server; + } + + Builder responseCode(final int code) { + this.responseCode = code; + return this; + } + + Builder body(final String body) { + this.body = body; + return this; + } + + HyperwalletMockResponse build() { + return new HyperwalletMockResponse(this); + } + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java b/receipt/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java new file mode 100644 index 000000000..92a711f96 --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java @@ -0,0 +1,187 @@ +package com.hyperwallet.android.util; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.EditText; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.action.ViewActions; +import androidx.test.espresso.matcher.BoundedMatcher; + +import com.google.android.material.textfield.TextInputLayout; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import java.util.Objects; + +public class EspressoUtils { + + public static Matcher withHint(final String expectedHint) { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof TextInputLayout)) { + return false; + } + + String hint = Objects.toString(((TextInputLayout) view).getHint()); + return expectedHint.equals(hint); + } + + @Override + public void describeTo(Description description) { + description.appendText(expectedHint); + } + }; + } + + public static Matcher hasErrorText(final String expectedErrorMessage) { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof TextInputLayout)) { + return false; + } + + String errorMessage = Objects.toString(((TextInputLayout) view).getError()); + return expectedErrorMessage.equals(errorMessage); + } + + @Override + public void describeTo(Description description) { + description.appendText(expectedErrorMessage); + } + }; + } + + public static Matcher hasErrorText(final int resourceId) { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof TextInputLayout)) { + return false; + } + String expectedErrorMessage = view.getResources().getString(resourceId); + String errorMessage = Objects.toString(((TextInputLayout) view).getError()); + + return expectedErrorMessage.equals(errorMessage); + } + + @Override + public void describeTo(Description description) { + } + }; + } + + public static Matcher withDrawable(final int resourceId) { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof ImageView)) { + return false; + } + + Drawable drawable = ((ImageView) view).getDrawable(); + if (drawable == null) { + return false; + } + Drawable expectedDrawable = view.getContext().getResources().getDrawable(resourceId); + + Bitmap bitmap = getBitmap(drawable); + Bitmap expectedBitmap = getBitmap(expectedDrawable); + + return bitmap.sameAs(expectedBitmap); + } + + @Override + public void describeTo(Description description) { + } + }; + } + + public static Matcher atPosition(final int position, @NonNull final Matcher matcher) { + return new BoundedMatcher(RecyclerView.class) { + + @Override + protected boolean matchesSafely(final RecyclerView view) { + RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(position); + + if (viewHolder == null) { + return false; + } + + return matcher.matches(viewHolder.itemView); + } + + @Override + public void describeTo(Description description) { + description.appendText("has item at position " + position + ": "); + matcher.describeTo(description); + } + }; + } + + public static ViewAction nestedScrollTo() { + return ViewActions.actionWithAssertions(new NestedScrollToAction()); + } + + private static Bitmap getBitmap(Drawable drawable) { + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + + return bitmap; + } + + public static Matcher hasNoErrorText() { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof TextInputLayout)) { + return false; + } + return ((TextInputLayout) view).getError() == null; + } + + @Override + public void describeTo(Description description) { + description.appendText("has no error text: "); + } + }; + } + + public static Matcher hasEmptyText() { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof EditText)) { + return false; + } + String text = ((EditText) view).getText().toString(); + + return text.isEmpty(); + } + + @Override + public void describeTo(Description description) { + } + }; + } +} + diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java b/receipt/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java new file mode 100644 index 000000000..392867387 --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java @@ -0,0 +1,41 @@ +package com.hyperwallet.android.util; + +import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; +import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; + +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.anyOf; + +import android.view.View; + +import androidx.core.widget.NestedScrollView; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.action.ScrollToAction; +import androidx.test.espresso.matcher.ViewMatchers; + +import org.hamcrest.Matcher; + +public class NestedScrollToAction implements ViewAction { + private static final String TAG = ScrollToAction.class.getSimpleName(); + + @SuppressWarnings("unchecked") + @Override + public Matcher getConstraints() { + return allOf( + withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), + isDescendantOfA( + anyOf(isAssignableFrom(NestedScrollView.class)))); + } + + @Override + public void perform(UiController uiController, View view) { + new ScrollToAction().perform(uiController, view); + } + + @Override + public String getDescription() { + return "scroll to"; + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java b/receipt/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java new file mode 100644 index 000000000..bb3aecaff --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java @@ -0,0 +1,30 @@ +package com.hyperwallet.android.util; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.espresso.ViewAssertion; + +public class RecyclerViewCountAssertion implements ViewAssertion { + private final int mCount; + + public RecyclerViewCountAssertion(int count) { + this.mCount = count; + } + + @Override + public void check(View view, NoMatchingViewException noViewFoundException) { + if (noViewFoundException != null) { + throw noViewFoundException; + } + + RecyclerView recyclerView = (RecyclerView) view; + RecyclerView.Adapter adapter = recyclerView.getAdapter(); + + assertThat(adapter.getItemCount(), is(mCount)); + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java b/receipt/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java new file mode 100644 index 000000000..686ccbf30 --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java @@ -0,0 +1,51 @@ +package com.hyperwallet.android.util; + +import com.hyperwallet.android.HyperwalletAuthenticationTokenListener; +import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.UUID; + +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +public class TestAuthenticationProvider implements HyperwalletAuthenticationTokenProvider { + + public static final MediaType JSON + = MediaType.get("application/json; charset=utf-8"); + private static final String mBaseUrl = "http://localhost:8080/rest/v3/users/{0}/authentication-token"; + private static final String mUserToken = "user_token"; + + @Override + public void retrieveAuthenticationToken(final HyperwalletAuthenticationTokenListener authenticationTokenListener) { + + OkHttpClient client = new OkHttpClient(); + + String payload = "{}"; + String baseUrl = MessageFormat.format(mBaseUrl, mUserToken); + + RequestBody body = RequestBody.create(JSON, payload); + Request request = new Request.Builder() + .url(baseUrl) + .post(body) + .build(); + + client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + authenticationTokenListener.onFailure(UUID.randomUUID(), e.getMessage()); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + authenticationTokenListener.onSuccess(response.body().string()); + } + }); + } +} diff --git a/receipt/src/main/AndroidManifest.xml b/receipt/src/main/AndroidManifest.xml index bf6f4ad0c..3039f6d18 100644 --- a/receipt/src/main/AndroidManifest.xml +++ b/receipt/src/main/AndroidManifest.xml @@ -1,2 +1,13 @@ - + + + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSource.java b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSource.java new file mode 100644 index 000000000..5320214fb --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSource.java @@ -0,0 +1,189 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.repository; + +import android.os.Handler; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.paging.PageKeyedDataSource; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.common.viewmodel.Event; +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.listener.HyperwalletListener; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.paging.HyperwalletPageList; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.model.receipt.ReceiptQueryParam; + +import java.util.Calendar; + +/** + * ReceiptDataSource mediates communication to HW API Platform particularly on + * Receipts V3 API + */ +public class ReceiptDataSource extends PageKeyedDataSource { + + private static final int YEAR_BEFORE_NOW = -1; + private final Calendar mCalendarYearBeforeNow; + private final MutableLiveData> mErrors = new MutableLiveData<>(); + private final MutableLiveData mIsFetchingData = new MutableLiveData<>(); + private LoadInitialCallback mLoadInitialCallback; + private LoadInitialParams mLoadInitialParams; + private LoadCallback mLoadAfterCallback; + private LoadParams mLoadAfterParams; + + ReceiptDataSource() { + super(); + mCalendarYearBeforeNow = Calendar.getInstance(); + mCalendarYearBeforeNow.add(Calendar.YEAR, YEAR_BEFORE_NOW); + } + + /** + * @see {@link PageKeyedDataSource#loadInitial(LoadInitialParams, LoadInitialCallback)} + */ + @Override + public void loadInitial(@NonNull final LoadInitialParams params, + @NonNull final LoadInitialCallback callback) { + mLoadInitialCallback = callback; + mLoadInitialParams = params; + mIsFetchingData.postValue(Boolean.TRUE); + + ReceiptQueryParam queryParam = new ReceiptQueryParam.Builder() + .createdAfter(mCalendarYearBeforeNow.getTime()) + .limit(params.requestedLoadSize) + .sortByCreatedOnDesc().build(); + + getHyperwallet().listReceipts(queryParam, + new HyperwalletListener>() { + @Override + public void onSuccess(@Nullable HyperwalletPageList result) { + mIsFetchingData.postValue(Boolean.FALSE); + mErrors.postValue(null); + + if (result != null) { + int next = result.getLimit() + result.getOffset(); + int previous = 0; + callback.onResult(result.getDataList(), previous, next); + } + // reset + mLoadInitialCallback = null; + mLoadInitialParams = null; + } + + @Override + public void onFailure(HyperwalletException exception) { + mIsFetchingData.postValue(Boolean.FALSE); + mErrors.postValue(new Event<>(exception.getHyperwalletErrors())); + } + + @Override + public Handler getHandler() { + return null; + } + }); + } + + /** + * Unused in this case + * + * @see {@link PageKeyedDataSource#loadBefore(LoadParams, LoadCallback)} + */ + @Override + public void loadBefore(@NonNull LoadParams params, + @NonNull LoadCallback callback) { + } + + /** + * @see {@link PageKeyedDataSource#loadAfter(LoadParams, LoadCallback)} + * */ + @Override + public void loadAfter(@NonNull LoadParams params, + final @NonNull LoadCallback callback) { + mLoadInitialCallback = null; + mLoadInitialParams = null; + mLoadAfterCallback = callback; + mLoadAfterParams = params; + mIsFetchingData.postValue(Boolean.TRUE); + + ReceiptQueryParam queryParam = new ReceiptQueryParam.Builder() + .createdAfter(mCalendarYearBeforeNow.getTime()) + .limit(params.requestedLoadSize) + .offset(params.key) + .sortByCreatedOnDesc().build(); + + getHyperwallet().listReceipts(queryParam, + new HyperwalletListener>() { + @Override + public void onSuccess(@Nullable HyperwalletPageList result) { + mIsFetchingData.postValue(Boolean.FALSE); + mErrors.postValue(null); + + if (result != null) { + int next = result.getLimit() + result.getOffset(); + callback.onResult(result.getDataList(), next); + } + + // reset + mLoadAfterCallback = null; + mLoadAfterParams = null; + } + + @Override + public void onFailure(HyperwalletException exception) { + mIsFetchingData.postValue(Boolean.FALSE); + mErrors.postValue(new Event<>(exception.getHyperwalletErrors())); + } + + @Override + public Handler getHandler() { + return null; + } + }); + } + + /** + * Facilitates retry when network is down; any error that we can have a retry operation + * */ + void retry() { + if (mLoadInitialCallback != null) { + loadInitial(mLoadInitialParams, mLoadInitialCallback); + } else if (mLoadAfterCallback != null) { + loadAfter(mLoadAfterParams, mLoadAfterCallback); + } + } + + /** + * Retrieve reference of Hyperwallet errors inorder for consumers to observe on data changes + * + * @return Live event data of {@link HyperwalletErrors} + * */ + public LiveData> getErrors() { + return mErrors; + } + + LiveData isFetchingData() { + return mIsFetchingData; + } + + Hyperwallet getHyperwallet() { + return Hyperwallet.getDefault(); + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactory.java b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactory.java new file mode 100644 index 000000000..a2b81216b --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactory.java @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.repository; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.paging.DataSource; + +/** + * Data source factory that uses {@link DataSource.Factory} facility + */ +public class ReceiptDataSourceFactory extends DataSource.Factory { + + private final MutableLiveData mDataSourceMutableLiveData; + private final ReceiptDataSource mReceiptDataSource; + + ReceiptDataSourceFactory() { + super(); + mReceiptDataSource = new ReceiptDataSource(); + mDataSourceMutableLiveData = new MutableLiveData<>(); + mDataSourceMutableLiveData.setValue(mReceiptDataSource); + } + + /** + * Returns observable members of receipt data source + */ + LiveData getReceiptDataSource() { + return mDataSourceMutableLiveData; + } + + /** + * @see {@link DataSource.Factory#create()} + */ + @NonNull + @Override + public DataSource create() { + return mReceiptDataSource; + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepository.java b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepository.java new file mode 100644 index 000000000..542d03c89 --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepository.java @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.repository; + +import androidx.lifecycle.LiveData; +import androidx.paging.PagedList; + +import com.hyperwallet.android.common.viewmodel.Event; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; + +/** + * Receipt Repository Contract + */ +public interface ReceiptRepository { + + /** + * Load receipts information, consumer can subscribe to receipts data changes events + * + * @return live data paged receipts + */ + LiveData> loadReceipts(); + + /** + * Loading indicator consumer can subscribe to loading of data events + * + * @return live data true if load receipt is in loading state; false otherwise + */ + LiveData isLoading(); + + /** + * Error information, consumer can subscribe of errors occur during data retrieval + * + * @return live event data list of errors if there's an error + */ + LiveData> getErrors(); + + /** + * Reload receipt information, usually invoked when error is raised after the first load and consumer opts to retry + * the last operation + */ + void retryLoadReceipt(); + +} diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactory.java b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactory.java new file mode 100644 index 000000000..b096ab7a0 --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactory.java @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.repository; + +/** + * {@link ReceiptRepository} factory + */ +public class ReceiptRepositoryFactory { + + private static ReceiptRepositoryFactory sInstance; + private final ReceiptRepository mReceiptRepository; + + private ReceiptRepositoryFactory() { + mReceiptRepository = new ReceiptRepositoryImpl(); + } + + /** + * Creates context single instance of this Factory + * + * @return receipt repository factory instance + */ + public static synchronized ReceiptRepositoryFactory getInstance() { + if (sInstance == null) { + sInstance = new ReceiptRepositoryFactory(); + } + return sInstance; + } + + /** + * Clears instance of repository factory + */ + public static void clearInstance() { + sInstance = null; + } + + /** + * @return ReceiptRepository instance implementation + * */ + public ReceiptRepository getReceiptRepository() { + return mReceiptRepository; + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryImpl.java b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryImpl.java new file mode 100644 index 000000000..cde7edd94 --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryImpl.java @@ -0,0 +1,93 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.repository; + +import androidx.lifecycle.LiveData; +import androidx.paging.LivePagedListBuilder; +import androidx.paging.PagedList; + +import com.hyperwallet.android.common.viewmodel.Event; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; + +/** + * {@link ReceiptRepository} implementation + */ +public class ReceiptRepositoryImpl implements ReceiptRepository { + + private static final int PAGE_SIZE = 10; + private static final int INITIAL_LOAD_SIZE = 20; + + private final ReceiptDataSourceFactory mDataSourceFactory; + private final LiveData mReceiptDataSourceLiveData; + private LiveData> mErrorsLiveData; + private LiveData mIsFetchingData; + private LiveData> mReceiptsLiveData; + + ReceiptRepositoryImpl() { + mDataSourceFactory = new ReceiptDataSourceFactory(); + mReceiptDataSourceLiveData = mDataSourceFactory.getReceiptDataSource(); + } + + /** + * @see {@link ReceiptRepository#loadReceipts()} + */ + @Override + public LiveData> loadReceipts() { + if (mReceiptsLiveData == null) { + PagedList.Config config = new PagedList.Config.Builder() + .setPageSize(PAGE_SIZE) + .setEnablePlaceholders(true) + .setInitialLoadSizeHint(INITIAL_LOAD_SIZE) + .build(); + mReceiptsLiveData = new LivePagedListBuilder<>(mDataSourceFactory, config).build(); + } + return mReceiptsLiveData; + } + + /** + * @see {@link ReceiptRepository#isLoading()} + */ + @Override + public LiveData isLoading() { + if (mIsFetchingData == null) { + mIsFetchingData = mReceiptDataSourceLiveData.getValue().isFetchingData(); + } + return mIsFetchingData; + } + + /** + * @see {@link ReceiptRepository#getErrors()} + * */ + @Override + public LiveData> getErrors() { + if (mErrorsLiveData == null) { + mErrorsLiveData = mReceiptDataSourceLiveData.getValue().getErrors(); + } + return mErrorsLiveData; + } + + /** + * @see {@link ReceiptRepository#retryLoadReceipt()} + * */ + @Override + public void retryLoadReceipt() { + if (mReceiptDataSourceLiveData.getValue() != null) { + mReceiptDataSourceLiveData.getValue().retry(); + } + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptActivity.java b/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptActivity.java new file mode 100644 index 000000000..e7f57c821 --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptActivity.java @@ -0,0 +1,133 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.view; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; + +import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.common.view.error.OnNetworkErrorCallback; +import com.hyperwallet.android.common.viewmodel.Event; +import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.receipt.R; +import com.hyperwallet.android.receipt.repository.ReceiptRepositoryFactory; +import com.hyperwallet.android.receipt.viewmodel.ListReceiptViewModel; + +import java.util.List; + +public class ListReceiptActivity extends AppCompatActivity implements OnNetworkErrorCallback { + + private ListReceiptViewModel mListReceiptViewModel; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_list_receipt); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + getSupportActionBar().setTitle(R.string.title_activity_receipt_list); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + ReceiptRepositoryFactory factory = ReceiptRepositoryFactory.getInstance(); + mListReceiptViewModel = ViewModelProviders.of(this, new ListReceiptViewModel + .ListReceiptViewModelFactory(factory.getReceiptRepository())) + .get(ListReceiptViewModel.class); + + mListReceiptViewModel.getReceiptErrors().observe(this, new Observer>() { + @Override + public void onChanged(Event event) { + if (event != null && !event.isContentConsumed()) { + showErrorOnLoadReceipt(event.getContent().getErrors()); + } + } + }); + + if (savedInstanceState == null) { + initFragment(ListReceiptFragment.newInstance()); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + ReceiptRepositoryFactory.clearInstance(); + } + + @Override + protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) { + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } + + private void initFragment(@NonNull final Fragment fragment) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.add(R.id.list_receipt_fragment, fragment); + fragmentTransaction.commit(); + } + + @Override + public void retry() { + FragmentManager fragmentManager = getSupportFragmentManager(); + ListReceiptFragment fragment = (ListReceiptFragment) + fragmentManager.findFragmentById(R.id.list_receipt_fragment); + + if (fragment == null) { + fragment = ListReceiptFragment.newInstance(); + } + fragment.retry(); + } + + private void showErrorOnLoadReceipt(@NonNull final List errors) { + FragmentManager fragmentManager = getSupportFragmentManager(); + DefaultErrorDialogFragment fragment = (DefaultErrorDialogFragment) + fragmentManager.findFragmentByTag(DefaultErrorDialogFragment.TAG); + + if (fragment == null) { + fragment = DefaultErrorDialogFragment.newInstance(errors); + } + + if (!fragment.isAdded()) { + fragment.show(fragmentManager); + } + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptFragment.java b/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptFragment.java new file mode 100644 index 000000000..ce6f9fd4d --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptFragment.java @@ -0,0 +1,264 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.view; + +import static com.hyperwallet.android.model.receipt.Receipt.Entries.CREDIT; +import static com.hyperwallet.android.model.receipt.Receipt.Entries.DEBIT; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; +import androidx.paging.PagedList; +import androidx.paging.PagedListAdapter; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.hyperwallet.android.common.util.DateUtils; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.receipt.R; +import com.hyperwallet.android.receipt.viewmodel.ListReceiptViewModel; + +import java.util.Calendar; +import java.util.Locale; +import java.util.Objects; + +public class ListReceiptFragment extends Fragment { + + private ListReceiptAdapter mListReceiptAdapter; + private RecyclerView mListReceiptsView; + private ListReceiptViewModel mListReceiptViewModel; + private View mProgressBar; + + /** + * Please don't use this constructor this is reserved for Android Core Framework + * + * @see {@link ListReceiptFragment#newInstance()} instead. + */ + public ListReceiptFragment() { + setRetainInstance(true); + } + + static ListReceiptFragment newInstance() { + ListReceiptFragment fragment = new ListReceiptFragment(); + return fragment; + } + + @Override + public void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mListReceiptViewModel = ViewModelProviders.of(requireActivity()).get( + ListReceiptViewModel.class); + } + + @Override + public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.list_receipt_fragment, container, false); + } + + @Override + public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mProgressBar = view.findViewById(R.id.list_receipt_progress_bar); + mListReceiptAdapter = new ListReceiptAdapter(new ListReceiptItemDiffCallback()); + mListReceiptsView = view.findViewById(R.id.list_receipts); + mListReceiptsView.setHasFixedSize(true); + mListReceiptsView.setLayoutManager(new LinearLayoutManager(getActivity())); + mListReceiptsView.addItemDecoration(new ReceiptItemDividerDecorator(requireContext(), false)); + mListReceiptsView.setAdapter(mListReceiptAdapter); + registerObservers(); + } + + private void registerObservers() { + mListReceiptViewModel.getReceiptList().observe(getViewLifecycleOwner(), new Observer>() { + @Override + public void onChanged(PagedList transferMethods) { + mListReceiptAdapter.submitList(transferMethods); + } + }); + + mListReceiptViewModel.isLoadingData().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(Boolean loading) { + if (loading) { + mProgressBar.setVisibility(View.VISIBLE); + } else { + mProgressBar.setVisibility(View.GONE); + } + } + }); + } + + void retry() { + mListReceiptViewModel.retryLoadReceipts(); + } + + private static class ListReceiptItemDiffCallback extends DiffUtil.ItemCallback { + + @Override + public boolean areItemsTheSame(@NonNull final Receipt oldItem, @NonNull final Receipt newItem) { + return oldItem.hashCode() == newItem.hashCode() + && Objects.equals(oldItem, newItem); + } + + @Override + public boolean areContentsTheSame(@NonNull final Receipt oldItem, @NonNull final Receipt newItem) { + return oldItem.hashCode() == newItem.hashCode() + && Objects.equals(oldItem, newItem); + } + } + + private static class ListReceiptAdapter + extends PagedListAdapter { + + private static final String HEADER_DATE_FORMAT = "MMMM yyyy"; + private static final String CAPTION_DATE_FORMAT = "MMMM dd, yyyy"; + private static final int HEADER_VIEW_TYPE = 1; + private static final int DATA_VIEW_TYPE = 0; + + ListReceiptAdapter(@NonNull final DiffUtil.ItemCallback diffCallback) { + super(diffCallback); + } + + @Override + public int getItemViewType(final int position) { + if (position != 0) { + Receipt previous = getItem(position - 1); + Receipt current = getItem(position); + if (isDataViewType(previous, current)) { + return DATA_VIEW_TYPE; + } + } + return HEADER_VIEW_TYPE; + } + + boolean isDataViewType(@NonNull final Receipt previous, @NonNull final Receipt current) { + Calendar prev = Calendar.getInstance(); + prev.setTime(DateUtils.fromDateTimeString(previous.getCreatedOn())); + Calendar curr = Calendar.getInstance(); + curr.setTime(DateUtils.fromDateTimeString(current.getCreatedOn())); + + return prev.get(Calendar.MONTH) == curr.get(Calendar.MONTH) + && prev.get(Calendar.YEAR) == curr.get(Calendar.YEAR); + } + + @NonNull + @Override + public ReceiptViewHolder onCreateViewHolder(final @NonNull ViewGroup viewGroup, int viewType) { + LayoutInflater layout = LayoutInflater.from(viewGroup.getContext()); + + if (viewType == HEADER_VIEW_TYPE) { + View headerView = layout.inflate(R.layout.item_receipt_with_header, viewGroup, false); + return new ReceiptViewHolderWithHeader(headerView); + } + View dataView = layout.inflate(R.layout.item_receipt, viewGroup, false); + return new ReceiptViewHolder(dataView); + } + + @Override + public void onBindViewHolder(@NonNull final ReceiptViewHolder holder, final int position) { + final Receipt receipt = getItem(position); + if (receipt != null) { + holder.bind(receipt); + } + } + + class ReceiptViewHolder extends RecyclerView.ViewHolder { + private final TextView mTransactionAmount; + private final TextView mTransactionCurrency; + private final TextView mTransactionDate; + private final TextView mTransactionTitle; + private final TextView mTransactionTypeIcon; + + ReceiptViewHolder(@NonNull final View item) { + super(item); + mTransactionAmount = item.findViewById(R.id.transaction_amount); + mTransactionCurrency = item.findViewById(R.id.transaction_currency); + mTransactionDate = item.findViewById(R.id.transaction_date); + mTransactionTitle = item.findViewById(R.id.transaction_title); + mTransactionTypeIcon = item.findViewById(R.id.transaction_type_icon); + } + + void bind(@NonNull final Receipt receipt) { + if (CREDIT.equals(receipt.getEntry())) { + mTransactionAmount.setTextColor(mTransactionAmount.getContext() + .getResources().getColor(R.color.positiveColor)); + mTransactionAmount.setText(mTransactionAmount.getContext() + .getString(R.string.credit_sign, receipt.getAmount())); + mTransactionTypeIcon.setTextColor(mTransactionTypeIcon.getContext() + .getResources().getColor(R.color.positiveColor)); + mTransactionTypeIcon.setBackground(mTransactionTypeIcon.getContext() + .getDrawable(R.drawable.circle_positive)); + mTransactionTypeIcon.setText(mTransactionTypeIcon.getContext().getText(R.string.credit)); + } else if (DEBIT.equals(receipt.getEntry())) { + mTransactionAmount.setTextColor(mTransactionAmount.getContext() + .getResources().getColor(R.color.colorAccent)); + mTransactionAmount.setText(mTransactionAmount.getContext() + .getString(R.string.debit_sign, receipt.getAmount())); + mTransactionTypeIcon.setTextColor(mTransactionTypeIcon.getContext() + .getResources().getColor(R.color.colorAccent)); + mTransactionTypeIcon.setBackground(mTransactionTypeIcon.getContext() + .getDrawable(R.drawable.circle_negative)); + mTransactionTypeIcon.setText(mTransactionTypeIcon.getContext().getText(R.string.debit)); + } + + mTransactionCurrency.setText(receipt.getCurrency()); + mTransactionTitle.setText(getTransactionTitle(receipt.getType(), mTransactionTitle.getContext())); + mTransactionDate.setText(DateUtils.toDateFormat(DateUtils. + fromDateTimeString(receipt.getCreatedOn()), CAPTION_DATE_FORMAT)); + } + + String getTransactionTitle(@NonNull final String receiptType, @NonNull final Context context) { + String showTitle = context.getResources().getString(R.string.unknown_type); + int resourceId = context.getResources().getIdentifier(receiptType.toLowerCase(Locale.ROOT), "string", + context.getPackageName()); + if (resourceId != 0) { + showTitle = context.getResources().getString(resourceId); + } + + return showTitle; + } + } + + class ReceiptViewHolderWithHeader extends ReceiptViewHolder { + + private final TextView mTransactionHeaderText; + + ReceiptViewHolderWithHeader(@NonNull final View item) { + super(item); + mTransactionHeaderText = item.findViewById(R.id.item_date_header_title); + } + + @Override + void bind(@NonNull final Receipt receipt) { + super.bind(receipt); + mTransactionHeaderText.setText(DateUtils.toDateFormat( + DateUtils.fromDateTimeString(receipt.getCreatedOn()), HEADER_DATE_FORMAT)); + } + } + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/view/ReceiptItemDividerDecorator.java b/receipt/src/main/java/com/hyperwallet/android/receipt/view/ReceiptItemDividerDecorator.java new file mode 100644 index 000000000..c61b22e5d --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/receipt/view/ReceiptItemDividerDecorator.java @@ -0,0 +1,102 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.hyperwallet.android.common.view.HorizontalDividerItemDecorator; + +public class ReceiptItemDividerDecorator extends HorizontalDividerItemDecorator { + + ReceiptItemDividerDecorator(@NonNull final Context context, final boolean withHeaderDivider) { + super(context, withHeaderDivider); + } + + @Override + public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + int right = parent.getWidth() - parent.getPaddingRight(); + + int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; i++) { + int left = 0; + int top; + int bottom; + View child = parent.getChildAt(i); + RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + + if (i == 0) { // first + // draw top + top = child.getTop() + params.topMargin; + bottom = top + mHorizontalItemDivider.getIntrinsicHeight(); + mHorizontalItemDivider.setBounds(left, top, right, bottom); + mHorizontalItemDivider.draw(c); + + if (childCount > 1) { // draw bottom + if (child instanceof LinearLayout) { // receipt header + // peek if next is a header then draw line from beginning + if (parent.getChildAt(i + 1) != null + && parent.getChildAt(i + 1) instanceof LinearLayout) { + left = 0; + } else { + left = ((ViewGroup) ((ViewGroup) child).getChildAt(1)).getChildAt(1).getLeft(); + } + } else { // receipt item + // peek if next is a header then draw line from beginning + if (parent.getChildAt(i + 1) != null + && parent.getChildAt(i + 1) instanceof LinearLayout) { + left = 0; + } else { + left = ((ViewGroup) child).getChildAt(1).getLeft(); + } + } + } + top = child.getBottom() + params.bottomMargin; + } else if (i == parent.getChildCount() - 1) { // draw bottom + top = child.getBottom() + params.bottomMargin; + } else { //draw middle + if (child instanceof LinearLayout) { // header found + // peek if next is a header then draw line from beginning + if (parent.getChildAt(i + 1) != null + && parent.getChildAt(i + 1) instanceof LinearLayout) { + left = 0; + } else { + left = ((ViewGroup) ((ViewGroup) child).getChildAt(1)).getChildAt(1).getLeft(); + } + } else { // non header + // peek if next is a header then draw line from beginning + if (parent.getChildAt(i + 1) != null + && parent.getChildAt(i + 1) instanceof LinearLayout) { + left = 0; + } else { + left = ((ViewGroup) child).getChildAt(1).getLeft(); + } + } + top = child.getBottom() + params.bottomMargin; + } + bottom = top + mHorizontalItemDivider.getIntrinsicHeight(); + mHorizontalItemDivider.setBounds(left, top, right, bottom); + mHorizontalItemDivider.draw(c); + } + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/viewmodel/ListReceiptViewModel.java b/receipt/src/main/java/com/hyperwallet/android/receipt/viewmodel/ListReceiptViewModel.java new file mode 100644 index 000000000..57f41b5c1 --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/receipt/viewmodel/ListReceiptViewModel.java @@ -0,0 +1,93 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.viewmodel; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; +import androidx.paging.PagedList; + +import com.hyperwallet.android.common.viewmodel.Event; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.receipt.repository.ReceiptRepository; + +public class ListReceiptViewModel extends ViewModel { + + private MutableLiveData> mErrorEvent = new MutableLiveData<>(); + private Observer> mErrorEventObserver; + private ReceiptRepository mReceiptRepository; + + private ListReceiptViewModel(@NonNull final ReceiptRepository receiptRepository) { + mReceiptRepository = receiptRepository; + // load initial receipts + mReceiptRepository.loadReceipts(); + + // register one time error event observer + mErrorEventObserver = new Observer>() { + @Override + public void onChanged(Event event) { + mErrorEvent.postValue(event); + } + }; + mReceiptRepository.getErrors().observeForever(mErrorEventObserver); + } + + public LiveData isLoadingData() { + return mReceiptRepository.isLoading(); + } + + public LiveData> getReceiptErrors() { + return mErrorEvent; + } + + public LiveData> getReceiptList() { + return mReceiptRepository.loadReceipts(); + } + + public void retryLoadReceipts() { + mReceiptRepository.retryLoadReceipt(); + } + + @Override + protected void onCleared() { + super.onCleared(); + mReceiptRepository.getErrors().removeObserver(mErrorEventObserver); + mReceiptRepository = null; + } + + public static class ListReceiptViewModelFactory implements ViewModelProvider.Factory { + + private final ReceiptRepository mReceiptRepository; + + public ListReceiptViewModelFactory(@NonNull final ReceiptRepository receiptRepository) { + mReceiptRepository = receiptRepository; + } + + @NonNull + @Override + public T create(@NonNull Class modelClass) { + if (modelClass.isAssignableFrom(ListReceiptViewModel.class)) { + return (T) new ListReceiptViewModel(mReceiptRepository); + } + throw new IllegalArgumentException("Expecting ViewModel class: " + ListReceiptViewModel.class.getName()); + } + } +} diff --git a/receipt/src/main/res/drawable/circle_negative.xml b/receipt/src/main/res/drawable/circle_negative.xml new file mode 100644 index 000000000..c7ae00b18 --- /dev/null +++ b/receipt/src/main/res/drawable/circle_negative.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/receipt/src/main/res/drawable/circle_positive.xml b/receipt/src/main/res/drawable/circle_positive.xml new file mode 100644 index 000000000..8b6506627 --- /dev/null +++ b/receipt/src/main/res/drawable/circle_positive.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/receipt/src/main/res/drawable/item_view_border.xml b/receipt/src/main/res/drawable/item_view_border.xml new file mode 100644 index 000000000..1bd67efd9 --- /dev/null +++ b/receipt/src/main/res/drawable/item_view_border.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/drawable/item_view_border_header.xml b/receipt/src/main/res/drawable/item_view_border_header.xml new file mode 100644 index 000000000..cceee0055 --- /dev/null +++ b/receipt/src/main/res/drawable/item_view_border_header.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/layout/activity_list_receipt.xml b/receipt/src/main/res/layout/activity_list_receipt.xml new file mode 100644 index 000000000..44beb1444 --- /dev/null +++ b/receipt/src/main/res/layout/activity_list_receipt.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/layout/item_receipt.xml b/receipt/src/main/res/layout/item_receipt.xml new file mode 100644 index 000000000..4388d4ab7 --- /dev/null +++ b/receipt/src/main/res/layout/item_receipt.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/layout/item_receipt_with_header.xml b/receipt/src/main/res/layout/item_receipt_with_header.xml new file mode 100644 index 000000000..29f002169 --- /dev/null +++ b/receipt/src/main/res/layout/item_receipt_with_header.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/layout/list_receipt_fragment.xml b/receipt/src/main/res/layout/list_receipt_fragment.xml new file mode 100644 index 000000000..52e9725db --- /dev/null +++ b/receipt/src/main/res/layout/list_receipt_fragment.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/values/colors.xml b/receipt/src/main/res/values/colors.xml new file mode 100644 index 000000000..89155ac94 --- /dev/null +++ b/receipt/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #FEF7F7 + #5FBF00 + #F1FAE8 + diff --git a/receipt/src/main/res/values/dimens.xml b/receipt/src/main/res/values/dimens.xml new file mode 100644 index 000000000..999d990b2 --- /dev/null +++ b/receipt/src/main/res/values/dimens.xml @@ -0,0 +1,6 @@ + + 3dp + 10dp + 8dp + 70dp + diff --git a/receipt/src/main/res/values/strings.xml b/receipt/src/main/res/values/strings.xml index c3ca11b97..6c6730a9e 100644 --- a/receipt/src/main/res/values/strings.xml +++ b/receipt/src/main/res/values/strings.xml @@ -1,6 +1,21 @@ receipt + Transactions + Seems like, you don\'t have any Transactions, + yet. + + Transfer Funds + \uE900 + Placeholder + + + \uE900 + \uE902 + - %s + + %s + + Unknown Transaction Type Annual Fee Annual Fee Refund Customer Service Fee diff --git a/receipt/src/main/res/values/styles.xml b/receipt/src/main/res/values/styles.xml new file mode 100644 index 000000000..b27a3a524 --- /dev/null +++ b/receipt/src/main/res/values/styles.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/receipt/src/main/res/xml/network_security_config.xml b/receipt/src/main/res/xml/network_security_config.xml new file mode 100644 index 000000000..5e4ba9c97 --- /dev/null +++ b/receipt/src/main/res/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + localhost + + \ No newline at end of file diff --git a/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactoryTest.java b/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactoryTest.java new file mode 100644 index 000000000..cf5c63114 --- /dev/null +++ b/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactoryTest.java @@ -0,0 +1,38 @@ +package com.hyperwallet.android.receipt.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; + +import androidx.lifecycle.LiveData; +import androidx.paging.DataSource; + +import org.hamcrest.CoreMatchers; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ReceiptDataSourceFactoryTest { + + @Test + public void testGetReceiptDataSource_returnsLiveDataReceiptSource() { + // initialize + ReceiptDataSourceFactory dataSourceFactory = new ReceiptDataSourceFactory(); + // test + LiveData liveData = dataSourceFactory.getReceiptDataSource(); + // assert + assertThat(liveData, is(notNullValue())); + } + + @Test + public void testCreate_returnsDataSource() { + // initialize + ReceiptDataSourceFactory dataSourceFactory = new ReceiptDataSourceFactory(); + // test + DataSource dataSource = dataSourceFactory.create(); + // assert + assertThat(dataSource, is(notNullValue())); + assertThat(dataSource, CoreMatchers.instanceOf(ReceiptDataSource.class)); + } +} diff --git a/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceTest.java b/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceTest.java new file mode 100644 index 000000000..d09854710 --- /dev/null +++ b/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceTest.java @@ -0,0 +1,389 @@ +package com.hyperwallet.android.receipt.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.nullValue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import static com.hyperwallet.android.model.receipt.Receipt.Entries.CREDIT; +import static com.hyperwallet.android.model.receipt.Receipt.Entries.DEBIT; +import static com.hyperwallet.android.model.receipt.Receipt.ReceiptTypes.PAYMENT; +import static com.hyperwallet.android.model.receipt.Receipt.ReceiptTypes.TRANSFER_TO_BANK_ACCOUNT; + +import androidx.paging.PageKeyedDataSource; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.listener.HyperwalletListener; +import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.paging.HyperwalletPageList; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.model.receipt.ReceiptQueryParam; +import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; + +import org.hamcrest.Matchers; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.stubbing.Answer; +import org.robolectric.RobolectricTestRunner; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class ReceiptDataSourceTest { + + @Rule + public MockitoRule mMockito = MockitoJUnit.rule(); + @Rule + public HyperwalletExternalResourceManager mExternalResourceManager = new HyperwalletExternalResourceManager(); + + @Mock + private Hyperwallet mHyperwallet; + @Mock + private PageKeyedDataSource.LoadInitialParams mInitialParams; + @Mock + private PageKeyedDataSource.LoadInitialCallback mInitialCallback; + // can't be mocked due to params.key is of type Integer and autoboxing will not work with null to 0 + private final PageKeyedDataSource.LoadParams mLoadAfterParams = + new PageKeyedDataSource.LoadParams<>(10, 10); + @Mock + private PageKeyedDataSource.LoadCallback mLoadAfterCallback; + + @Captor + private ArgumentCaptor> mListArgumentCaptor; + @Captor + private ArgumentCaptor mPreviousCaptor; + @Captor + private ArgumentCaptor mNextCaptor; + + @Spy + private ReceiptDataSource mReceiptDataSource; + + @Before + public void setUp() { + doReturn(mHyperwallet).when(mReceiptDataSource).getHyperwallet(); + } + + @Test + public void testLoadInitial_returnsReceipts() throws Exception { + String json = mExternalResourceManager.getResourceContent("receipt_list_date_grouping_response.json"); + JSONObject jsonObject = new JSONObject(json); + final HyperwalletPageList response = new HyperwalletPageList<>(jsonObject, Receipt.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onSuccess(response); + return listener; + } + }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + + verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mInitialCallback).onResult(mListArgumentCaptor.capture(), mPreviousCaptor.capture(), + mNextCaptor.capture()); + + assertThat(mPreviousCaptor.getValue(), is(0)); + assertThat(mNextCaptor.getValue(), is(10)); + + // assert receipts information + List receipts = mListArgumentCaptor.getValue(); + assertThat(receipts, Matchers.hasSize(5)); + assertThat(receipts.get(0).getJournalId(), is("51660665")); + assertThat(receipts.get(0).getType(), is(PAYMENT)); + assertThat(receipts.get(0).getEntry(), is(CREDIT)); + assertThat(receipts.get(0).getSourceToken(), is("act-b1f6dc28-e534-45f4-a661-3523f051f77a")); + assertThat(receipts.get(0).getDestinationToken(), is("usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6")); + assertThat(receipts.get(0).getAmount(), is("5000.00")); + assertThat(receipts.get(0).getFee(), is("0.00")); + assertThat(receipts.get(0).getCurrency(), is("USD")); + assertThat(receipts.get(0).getDetails(), is(notNullValue())); + assertThat(receipts.get(0).getDetails().getPayeeName(), is("Kevin Puckett")); + assertThat(receipts.get(0).getDetails().getClientPaymentId(), is("trans-0001")); + assertThat(receipts.get(1).getJournalId(), is("51660666")); + assertThat(receipts.get(1).getType(), is(TRANSFER_TO_BANK_ACCOUNT)); + assertThat(receipts.get(1).getEntry(), is(DEBIT)); + assertThat(receipts.get(1).getSourceToken(), is("usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6")); + assertThat(receipts.get(1).getDestinationToken(), is("trm-0a2ac589-2cae-4ed3-9b0b-658246a34687")); + assertThat(receipts.get(1).getAmount(), is("10.25")); + assertThat(receipts.get(1).getFee(), is("0.25")); + assertThat(receipts.get(1).getCurrency(), is("USD")); + assertThat(receipts.get(1).getDetails(), is(notNullValue())); + assertThat(receipts.get(1).getDetails().getPayeeName(), is("Kevin Puckett")); + assertThat(receipts.get(1).getDetails().getBankAccountId(), is("patzachery.mcclary@example.com")); + + assertThat(mReceiptDataSource.getErrors().getValue(), is(nullValue())); + assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testLoadInitial_returnNoReceipt() { + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onSuccess(null); + return listener; + } + }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + + verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt(), anyInt()); + + assertThat(mReceiptDataSource.getErrors().getValue(), is(nullValue())); + assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testLoadInitial_withError() { + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + List errorList = new ArrayList<>(); + errorList.add(error); + final HyperwalletErrors errors = new HyperwalletErrors(errorList); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + + verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt(), anyInt()); + + assertThat(mReceiptDataSource.getErrors().getValue(), is(notNullValue())); + assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors(), + Matchers.hasSize(1)); + assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getCode(), + is("TEST_CODE")); + assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getMessage(), + is("test message")); + assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testRetry_loadInitial() { + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + List errorList = new ArrayList<>(); + errorList.add(error); + final HyperwalletErrors errors = new HyperwalletErrors(errorList); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + + verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt(), anyInt()); + + // error occurred, this will save params and callback + assertThat(mReceiptDataSource.getErrors().getValue(), is(notNullValue())); + + // test retry, saved params and callback will be used and no null pointer exception is thrown + mReceiptDataSource.retry(); + + // verify calls + verify(mReceiptDataSource, times(2)).loadInitial( + ArgumentMatchers.>any(), + ArgumentMatchers.>any()); + verify(mReceiptDataSource, never()).loadAfter( + ArgumentMatchers.>any(), + ArgumentMatchers.>any()); + } + + @Test + public void testLoadAfter_returnsReceipts() throws Exception { + String json = mExternalResourceManager.getResourceContent("receipt_list_date_grouping_response.json"); + JSONObject jsonObject = new JSONObject(json); + final HyperwalletPageList response = new HyperwalletPageList<>(jsonObject, Receipt.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onSuccess(response); + return listener; + } + }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + + verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mLoadAfterCallback).onResult(mListArgumentCaptor.capture(), mNextCaptor.capture()); + + assertThat(mNextCaptor.getValue(), is(10)); + + // assert receipts information + List receipts = mListArgumentCaptor.getValue(); + assertThat(receipts, Matchers.hasSize(5)); + assertThat(receipts.get(3).getJournalId(), is("51660675")); + assertThat(receipts.get(3).getType(), is(PAYMENT)); + assertThat(receipts.get(3).getEntry(), is(CREDIT)); + assertThat(receipts.get(3).getSourceToken(), is("act-b1f6dc28-e534-45f4-a661-3523f051f77a")); + assertThat(receipts.get(3).getDestinationToken(), is("usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6")); + assertThat(receipts.get(3).getAmount(), is("13.00")); + assertThat(receipts.get(3).getFee(), is("0.00")); + assertThat(receipts.get(3).getCurrency(), is("USD")); + assertThat(receipts.get(3).getDetails(), is(notNullValue())); + assertThat(receipts.get(3).getDetails().getPayeeName(), is("Kevin Puckett")); + assertThat(receipts.get(3).getDetails().getClientPaymentId(), is("CSietnRJQQ0bscYkOoPJxNiTDiVALhjQ")); + assertThat(receipts.get(4).getJournalId(), is("51660676")); + assertThat(receipts.get(4).getType(), is(PAYMENT)); + assertThat(receipts.get(4).getEntry(), is(CREDIT)); + assertThat(receipts.get(4).getSourceToken(), is("act-b1f6dc28-e534-45f4-a661-3523f051f77a")); + assertThat(receipts.get(4).getDestinationToken(), is("usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6")); + assertThat(receipts.get(4).getAmount(), is("14.00")); + assertThat(receipts.get(4).getFee(), is("0.00")); + assertThat(receipts.get(4).getCurrency(), is("USD")); + assertThat(receipts.get(4).getDetails(), is(notNullValue())); + assertThat(receipts.get(4).getDetails().getPayeeName(), is("Kevin Puckett")); + assertThat(receipts.get(4).getDetails().getClientPaymentId(), is("wUOdfLlJONacbdHlAHOAXQT7uwX7LTPy")); + + assertThat(mReceiptDataSource.getErrors().getValue(), is(nullValue())); + assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testLoadAfter_returnNoReceipt() { + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onSuccess(null); + return listener; + } + }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + + verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.>any(), anyInt()); + + assertThat(mReceiptDataSource.getErrors().getValue(), is(nullValue())); + assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testLoadAfter_withError() { + final HyperwalletError error = new HyperwalletError("test message load after", "LOAD_AFTER_CODE"); + List errorList = new ArrayList<>(); + errorList.add(error); + final HyperwalletErrors errors = new HyperwalletErrors(errorList); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + + verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt()); + + // error occurred, this will save params and callback + assertThat(mReceiptDataSource.getErrors().getValue(), is(notNullValue())); + assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors(), + Matchers.hasSize(1)); + assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getCode(), + is("LOAD_AFTER_CODE")); + assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getMessage(), + is("test message load after")); + assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testRetry_loadAfter() { + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + List errorList = new ArrayList<>(); + errorList.add(error); + final HyperwalletErrors errors = new HyperwalletErrors(errorList); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + + verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt()); + + // error occurred, this will save params and callback + assertThat(mReceiptDataSource.getErrors().getValue(), is(notNullValue())); + + // test retry, saved params and callback will be used and no null pointer exception is thrown + mReceiptDataSource.retry(); + + // verify calls + verify(mReceiptDataSource, times(2)).loadAfter( + ArgumentMatchers.>any(), + ArgumentMatchers.>any()); + verify(mReceiptDataSource, never()).loadInitial( + ArgumentMatchers.>any(), + ArgumentMatchers.>any()); + } +} diff --git a/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactoryTest.java b/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactoryTest.java new file mode 100644 index 000000000..3326f2916 --- /dev/null +++ b/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactoryTest.java @@ -0,0 +1,39 @@ +package com.hyperwallet.android.receipt.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ReceiptRepositoryFactoryTest { + + @Test + public void testGetInstance_verifyRepositoriesInitialized() { + // test + ReceiptRepositoryFactory factory = ReceiptRepositoryFactory.getInstance(); + assertThat(factory, is(notNullValue())); + assertThat(factory.getReceiptRepository(), is(notNullValue())); + + ReceiptRepositoryFactory factory2 = ReceiptRepositoryFactory.getInstance(); + assertThat(factory, is(factory2)); + assertThat(factory.getReceiptRepository(), is(factory2.getReceiptRepository())); + } + + @Test + public void testClearInstance_verifyRepositoriesCleared() { + ReceiptRepositoryFactory factory = ReceiptRepositoryFactory.getInstance(); + assertThat(factory, is(notNullValue())); + assertThat(factory.getReceiptRepository(), is(notNullValue())); + + // test clear + ReceiptRepositoryFactory.clearInstance(); + ReceiptRepositoryFactory factory2 = ReceiptRepositoryFactory.getInstance(); + assertThat(factory, is(not(factory2))); + assertThat(factory.getReceiptRepository(), is(not(factory2.getReceiptRepository()))); + } +} diff --git a/receipt/src/test/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java b/receipt/src/test/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java new file mode 100644 index 000000000..9061af9b8 --- /dev/null +++ b/receipt/src/test/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java @@ -0,0 +1,72 @@ +package com.hyperwallet.android.rule; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class HyperwalletExternalResourceManager extends TestWatcher { + + private static final String EMPTY = ""; + private ClassLoader classLoader; + private Logger logger; + + @Override + protected void starting(Description description) { + super.starting(description); + classLoader = description.getTestClass().getClassLoader(); + logger = Logger.getLogger(description.getTestClass().getName()); + } + + public String getResourceContent(final String resourceName) { + if (resourceName == null) { + throw new IllegalArgumentException("Parameter resourceName cannot be null"); + } + + return getContent(resourceName); + } + + private String getContent(final String resourceName) { + URL resource = classLoader.getResource(resourceName); + InputStream inputStream = null; + Writer writer = new StringWriter(); + String resourceContent = EMPTY; + if (resource != null) { + try { + inputStream = resource.openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + String line = reader.readLine(); + while (line != null) { + writer.write(line); + line = reader.readLine(); + } + resourceContent = writer.toString(); + + } catch (Exception e) { + logger.log(Level.WARNING, "There was an error loading an external resource", e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "There was an error closing input stream", e); + } + try { + writer.close(); + } catch (IOException e) { + logger.log(Level.SEVERE, "There was an error closing writer", e); + } + } + } + return resourceContent; + } +} diff --git a/receipt/src/test/resources/authentication_token_response.json b/receipt/src/test/resources/authentication_token_response.json new file mode 100644 index 000000000..e8e41bf37 --- /dev/null +++ b/receipt/src/test/resources/authentication_token_response.json @@ -0,0 +1,3 @@ +{ + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c3ItZjZlNmZjY2EtNTBmNy00ZWY1LWExYzUtNWZmMDJlMDU2MzgzIiwiaWF0IjoxNTQ5NTgwMzk0LCJleHAiOjI1NDk1ODA5OTQsImF1ZCI6InBndS03YTEyMzJlOC0xNDc5LTQzNzAtOWY1NC03ODc1ZjdiMTg2NmMiLCJpc3MiOiJwcmctY2NhODAyNWUtODVhMy0xMWU2LTg2MGEtNThhZDVlY2NlNjFkIiwicmVzdC11cmkiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVzdC92My8iLCJncmFwaHFsLXVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9ncmFwaHFsIn0.kILSynYHbepbl4sVqENnNog09iGByfTrckHhSCjVgnuRnuspI72cx3rt0SB2V_neHwzYkD_VfhNKk9gJDOwXeQ" +} \ No newline at end of file diff --git a/receipt/src/test/resources/receipt_credit_response.json b/receipt/src/test/resources/receipt_credit_response.json new file mode 100644 index 000000000..4351d17a2 --- /dev/null +++ b/receipt/src/test/resources/receipt_credit_response.json @@ -0,0 +1,30 @@ +{ + "count": 1, + "offset": 0, + "limit": 10, + "data": [ + { + "journalId": "3051581", + "type": "PAYMENT", + "createdOn": "2019-06-02T17:09:07", + "entry": "CREDIT", + "sourceToken": "act-12345", + "destinationToken": "usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d", + "amount": "25.00", + "fee": "0.00", + "currency": "CAD", + "details": { + "clientPaymentId": "ABC1234", + "payeeName": "A Person" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://api.sandbox.hyperwallet.com/rest/v3/users/usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d/receipts?offset=0&limit=10" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/receipt_debit_response.json b/receipt/src/test/resources/receipt_debit_response.json new file mode 100644 index 000000000..8ed756455 --- /dev/null +++ b/receipt/src/test/resources/receipt_debit_response.json @@ -0,0 +1,25 @@ +{ + "count": 1, + "offset": 0, + "limit": 10, + "data": [ + { + "journalId": "3051590", + "type": "TRANSFER_TO_PREPAID_CARD", + "createdOn": "2019-05-02T17:12:18", + "entry": "DEBIT", + "sourceToken": "usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d", + "destinationToken": "trm-12345", + "amount": "18.05", + "currency": "USD" + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://api.sandbox.hyperwallet.com/rest/v3/users/usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d/receipts?offset=0&limit=10" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/receipt_list_date_grouping_response.json b/receipt/src/test/resources/receipt_list_date_grouping_response.json new file mode 100644 index 000000000..d4d552972 --- /dev/null +++ b/receipt/src/test/resources/receipt_list_date_grouping_response.json @@ -0,0 +1,90 @@ +{ + "count": 5, + "offset": 0, + "limit": 10, + "data": [ + { + "journalId": "51660665", + "type": "PAYMENT", + "createdOn": "2019-05-27T15:42:07", + "entry": "CREDIT", + "sourceToken": "act-b1f6dc28-e534-45f4-a661-3523f051f77a", + "destinationToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "amount": "5000.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "trans-0001", + "payeeName": "Kevin Puckett" + } + }, + { + "journalId": "51660666", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-05-27T15:57:49", + "entry": "DEBIT", + "sourceToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "destinationToken": "trm-0a2ac589-2cae-4ed3-9b0b-658246a34687", + "amount": "10.25", + "fee": "0.25", + "currency": "USD", + "details": { + "payeeName": "Kevin Puckett", + "bankAccountId": "patzachery.mcclary@example.com" + } + }, + { + "journalId": "51660667", + "type": "PAYMENT", + "createdOn": "2019-05-27T16:01:10", + "entry": "CREDIT", + "sourceToken": "act-b1f6dc28-e534-45f4-a661-3523f051f77a", + "destinationToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "amount": "11.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "trans-02", + "payeeName": "Kevin Puckett" + } + }, + { + "journalId": "51660675", + "type": "PAYMENT", + "createdOn": "2019-06-04T10:35:23", + "entry": "CREDIT", + "sourceToken": "act-b1f6dc28-e534-45f4-a661-3523f051f77a", + "destinationToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "amount": "13.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "CSietnRJQQ0bscYkOoPJxNiTDiVALhjQ", + "payeeName": "Kevin Puckett" + } + }, + { + "journalId": "51660676", + "type": "PAYMENT", + "createdOn": "2019-06-04T11:16:21", + "entry": "CREDIT", + "sourceToken": "act-b1f6dc28-e534-45f4-a661-3523f051f77a", + "destinationToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "amount": "14.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "wUOdfLlJONacbdHlAHOAXQT7uwX7LTPy", + "payeeName": "Kevin Puckett" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6/receipts?offset=0&limit=10&createdAfter=2019-1-1" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/receipt_list_response.json b/receipt/src/test/resources/receipt_list_response.json new file mode 100644 index 000000000..7e7cc58af --- /dev/null +++ b/receipt/src/test/resources/receipt_list_response.json @@ -0,0 +1,64 @@ +{ + "count": 4, + "offset": 0, + "limit": 10, + "data": [ + { + "journalId": "3051579", + "type": "PAYMENT", + "createdOn": "2019-06-07T17:08:58", + "entry": "CREDIT", + "sourceToken": "act-12345", + "destinationToken": "usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d", + "amount": "20.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "8OxXefx5", + "payeeName": "A Person" + } + }, + { + "journalId": "3051581", + "type": "PAYMENT", + "createdOn": "2019-06-02T16:09:07", + "entry": "CREDIT", + "sourceToken": "act-12345", + "destinationToken": "usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d", + "amount": "25.00", + "fee": "0.00", + "currency": "CAD", + "details": { + "clientPaymentId": "Q3SVvpv0", + "payeeName": "A Person" + } + }, + { + "journalId": "3051582", + "type": "CARD_ACTIVATION_FEE", + "createdOn": "2019-06-01T11:09:16", + "entry": "DEBIT", + "sourceToken": "usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d", + "amount": "1.95", + "currency": "USD" + }, + { + "journalId": "3051590", + "type": "TRANSFER_TO_PREPAID_CARD", + "createdOn": "2018-12-01T17:12:18", + "entry": "DEBIT", + "sourceToken": "usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d", + "destinationToken": "trm-12345", + "amount": "18.05", + "currency": "USD" + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://api.sandbox.hyperwallet.com/rest/v3/users/usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d/receipts?offset=0&limit=10" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/receipt_unknown_type_response.json b/receipt/src/test/resources/receipt_unknown_type_response.json new file mode 100644 index 000000000..bf856ed63 --- /dev/null +++ b/receipt/src/test/resources/receipt_unknown_type_response.json @@ -0,0 +1,30 @@ +{ + "count": 1, + "offset": 0, + "limit": 10, + "data": [ + { + "journalId": "3051581", + "type": "ICK", + "createdOn": "2019-06-02T17:09:07", + "entry": "CREDIT", + "sourceToken": "act-12345", + "destinationToken": "usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d", + "amount": "25.00", + "fee": "0.00", + "currency": "CAD", + "details": { + "clientPaymentId": "ABC1234", + "payeeName": "A Person" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://api.sandbox.hyperwallet.com/rest/v3/users/usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d/receipts?offset=0&limit=10" + } + ] +} \ No newline at end of file diff --git a/ui/src/androidTest/AndroidManifest.xml b/ui/src/androidTest/AndroidManifest.xml index 9b2c52c35..0cd133def 100644 --- a/ui/src/androidTest/AndroidManifest.xml +++ b/ui/src/androidTest/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="com.hyperwallet.android.hyperwallet_ui.test"> diff --git a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java index d2f6b9123..aae63fa7e 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java @@ -31,6 +31,7 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; +import com.hyperwallet.android.receipt.view.ListReceiptActivity; import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; import com.hyperwallet.android.ui.transfermethod.ListTransferMethodActivity; import com.hyperwallet.android.ui.transfermethod.SelectTransferMethodActivity; @@ -78,6 +79,13 @@ public Intent getIntentSelectTransferMethodActivity(@NonNull final Context conte return new Intent(context, SelectTransferMethodActivity.class); } + /** + * @param context A Context of the application consuming this Intent. + * @return an Intent with the data necessary to launch the {@link ListReceiptActivity} + */ + public Intent getIntentListReceiptActivity(@NonNull final Context context) { + return new Intent(context, ListReceiptActivity.class); + } /** * @param context A Context of the application consuming this Intent. diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java index 7d6b77063..902971023 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java @@ -16,6 +16,7 @@ */ package com.hyperwallet.android.ui.repository; +import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.ACTIVATED; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TOKEN; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TYPE; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; @@ -36,6 +37,7 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount; import com.hyperwallet.android.model.transfermethod.HyperwalletBankCard; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethodQueryParam; import com.hyperwallet.android.model.transfermethod.PayPalAccount; public class TransferMethodRepositoryImpl implements TransferMethodRepository { @@ -66,7 +68,11 @@ public void createTransferMethod(@NonNull final HyperwalletTransferMethod transf @Override public void loadTransferMethods(@NonNull final LoadTransferMethodListCallback callback) { - getHyperwallet().listTransferMethods(null, + + HyperwalletTransferMethodQueryParam queryParam = new HyperwalletTransferMethodQueryParam.Builder() + .status(ACTIVATED) + .build(); + getHyperwallet().listTransferMethods(queryParam, new HyperwalletListener>() { @Override public void onSuccess(@Nullable HyperwalletPageList result) { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java index 385d827a6..d09829047 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java @@ -48,13 +48,13 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.hyperwallet.android.common.view.HorizontalDividerItemDecorator; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletStatusTransition; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.HyperwalletLocalBroadcast; import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.view.HorizontalDividerItemDecorator; import com.hyperwallet.android.ui.view.widget.OneClickListener; import java.util.ArrayList; @@ -178,7 +178,7 @@ public void onOneClick(View v) { recyclerView = view.findViewById(R.id.list_transfer_method_item); recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); - recyclerView.addItemDecoration(new HorizontalDividerItemDecorator(getContext(), false)); + recyclerView.addItemDecoration(new HorizontalDividerItemDecorator(requireContext(), false)); } @Override diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java index aa4a9408f..154a2bff0 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java @@ -38,12 +38,12 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.hyperwallet.android.common.view.HorizontalDividerItemDecorator; import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.view.CountrySelectionDialogFragment; import com.hyperwallet.android.ui.view.CurrencySelectionDialogFragment; -import com.hyperwallet.android.ui.view.HorizontalDividerItemDecorator; import com.hyperwallet.android.ui.view.widget.OneClickListener; import java.util.ArrayList; @@ -183,7 +183,7 @@ public void onTransferMethodSelected(TransferMethodSelectionItem transferMethodT mRecyclerView.setAdapter(mTransferMethodTypesAdapter); mRecyclerView.setHasFixedSize(true); mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); - mRecyclerView.addItemDecoration(new HorizontalDividerItemDecorator(getContext(), true)); + mRecyclerView.addItemDecoration(new HorizontalDividerItemDecorator(requireContext(), true)); } @Override diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java index 6135c42b2..334ad2044 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java @@ -33,7 +33,7 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount; import com.hyperwallet.android.model.transfermethod.HyperwalletBankCard; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; -import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethodPagination; +import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethodQueryParam; import com.hyperwallet.android.model.transfermethod.PayPalAccount; import org.junit.Before; @@ -423,7 +423,7 @@ public Object answer(InvocationOnMock invocation) { listener.onSuccess(pageList); return listener; } - }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodPagination) any(), + }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodQueryParam) any(), ArgumentMatchers.>>any()); // test @@ -448,7 +448,7 @@ public Object answer(InvocationOnMock invocation) { listener.onSuccess(null); return listener; } - }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodPagination) any(), + }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodQueryParam) any(), ArgumentMatchers.>>any()); // test @@ -475,7 +475,7 @@ public Object answer(InvocationOnMock invocation) { listener.onFailure(new HyperwalletException(errors)); return listener; } - }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodPagination) any(), + }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodQueryParam) any(), ArgumentMatchers.>>any()); // test From 6a570b8bc84cc679162ed3df2218f95d670b9097 Mon Sep 17 00:00:00 2001 From: Shyang Koong Date: Thu, 13 Jun 2019 14:18:01 -0700 Subject: [PATCH 014/177] Implement lazy loading automation and fixing lint error (#41) --- .../android/receipt/ListReceiptsTest.java | 35 ++ receipt/src/main/AndroidManifest.xml | 3 +- receipt/src/main/res/layout/item_receipt.xml | 1 + .../receipt_list_paged_last_response.json | 189 ++++++++++ .../receipt_list_paged_response.json | 351 ++++++++++++++++++ .../receipt_list_paged_second_response.json | 202 ++++++++++ .../receipt_list_paged_third_response.json | 201 ++++++++++ 7 files changed, 981 insertions(+), 1 deletion(-) create mode 100644 receipt/src/test/resources/receipt_list_paged_last_response.json create mode 100644 receipt/src/test/resources/receipt_list_paged_response.json create mode 100644 receipt/src/test/resources/receipt_list_paged_second_response.json create mode 100644 receipt/src/test/resources/receipt_list_paged_third_response.json diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java b/receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java index 5eb430354..05c0e5c59 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java +++ b/receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java @@ -22,6 +22,7 @@ import android.widget.TextView; import androidx.test.core.app.ApplicationProvider; +import androidx.test.espresso.contrib.RecyclerViewActions; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ActivityTestRule; @@ -229,6 +230,40 @@ public void testListReceipt_userHasNoTransactions() { //todo: check empty view when it will be ready } + @Test + public void testListReceipt_displayPagedTransactions() throws InterruptedException { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_list_paged_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_list_paged_second_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_list_paged_third_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_list_paged_last_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.toolbar)).check(matches(isDisplayed())); + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(20)); + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.scrollToPosition(10)); + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(30)); + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.scrollToPosition(20)); + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(40)); + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.scrollToPosition(30)); + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(50)); + + // verify that when the list reaches the end no additional data is loaded + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.scrollToPosition(40)); + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(50)); + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.scrollToPosition(50)); + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(50)); + } + @Test public void testListReceipts_checkDateTextOnLocaleChange() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager diff --git a/receipt/src/main/AndroidManifest.xml b/receipt/src/main/AndroidManifest.xml index 3039f6d18..3716721ff 100644 --- a/receipt/src/main/AndroidManifest.xml +++ b/receipt/src/main/AndroidManifest.xml @@ -1,10 +1,11 @@ - + diff --git a/receipt/src/main/res/layout/item_receipt.xml b/receipt/src/main/res/layout/item_receipt.xml index 4388d4ab7..83a0fe875 100644 --- a/receipt/src/main/res/layout/item_receipt.xml +++ b/receipt/src/main/res/layout/item_receipt.xml @@ -32,6 +32,7 @@ android:ellipsize="end" android:maxLines="1" android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1" + android:textStyle="bold" app:layout_constraintEnd_toStartOf="@+id/transaction_amount" app:layout_constraintStart_toEndOf="@+id/transaction_type_icon" app:layout_constraintTop_toTopOf="parent"/> diff --git a/receipt/src/test/resources/receipt_list_paged_last_response.json b/receipt/src/test/resources/receipt_list_paged_last_response.json new file mode 100644 index 000000000..be47b01ab --- /dev/null +++ b/receipt/src/test/resources/receipt_list_paged_last_response.json @@ -0,0 +1,189 @@ +{ + "count": 50, + "offset": 40, + "limit": 10, + "data": [ + { + "journalId": "55241289", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-01-05T20:29:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-cc13b0b0-5f4b-4c99-baed-eb16c8952f46", + "amount": "22.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "******9129", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241288", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-01-05T20:29:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-cc13b0b0-5f4b-4c99-baed-eb16c8952f46", + "amount": "17.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "******9129", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241287", + "type": "PAYMENT", + "createdOn": "2019-01-01T19:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "15.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "G2iCyydpjEYied0PFLfo2HyrEQg0VUYv", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241286", + "type": "PAYMENT", + "createdOn": "2019-01-01T19:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "90.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "1F81fMHy0Y1NPr6erbCTy67v3lcsMl4S", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241285", + "type": "PAYMENT", + "createdOn": "2019-01-01T19:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "80.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "AWab45eQg5XrMN1LG2WXS3jtKkMUjc01", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241284", + "type": "PAYMENT", + "createdOn": "2019-01-01T19:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "50.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "15MWFNmfEYaSp38NXyH7fw0jsrjKDB3h", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241283", + "type": "PAYMENT", + "createdOn": "2019-01-01T19:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "30.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "l06YPYvEiBYIjKSNV4lnMi5X1WagNxja", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241282", + "type": "PAYMENT", + "createdOn": "2019-01-01T19:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "30.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "jPq1QVXJDhAWMVsAU2Rnso1V3DLkudSY", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241281", + "type": "PAYMENT", + "createdOn": "2019-01-01T19:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "30.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "h42SUtuNGp7SJEvaAqaEkTjFmMDkGPWF", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241280", + "type": "PAYMENT", + "createdOn": "2019-01-01T19:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "99.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "lkrVqCxjYwxeDq2xr7PMa7eoLugC7ipk", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=40&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "previous" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=30&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "first" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=0&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/receipt_list_paged_response.json b/receipt/src/test/resources/receipt_list_paged_response.json new file mode 100644 index 000000000..d934b96c0 --- /dev/null +++ b/receipt/src/test/resources/receipt_list_paged_response.json @@ -0,0 +1,351 @@ +{ + "count": 50, + "offset": 0, + "limit": 20, + "data": [ + { + "journalId": "55452697", + "type": "PAYMENT", + "createdOn": "2019-06-07T23:43:51", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "100.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "bUxGdH3cMnMwmDkKNB6AWeDBXbcAw2eT", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241328", + "type": "PAYMENT", + "createdOn": "2019-05-31T22:20:46", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "57.00", + "fee": "0.00", + "currency": "CAD", + "details": { + "clientPaymentId": "CJOmbMXDSSosXNmoS8SOmukbwnPBWA6e", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241327", + "type": "PAYMENT", + "createdOn": "2019-05-31T21:00:02", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "45.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "QIai7gcuCNsl3CGnDLTEgCkKcQlvFjKU", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241326", + "type": "PAYMENT", + "createdOn": "2019-05-31T21:00:01", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "44.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "tyRdLmOeXtikCgeX1XEdCTTSfbpVWDxt", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241325", + "type": "PAYMENT", + "createdOn": "2019-05-31T20:59:59", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "70.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "7IJPL4LhiqVTSySkBoWkcB1Os2xRBvug", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241324", + "type": "PAYMENT", + "createdOn": "2019-05-31T20:59:58", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "20.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "HByAlgikQMEg0FuHJ8LxomEiPBhbP1FA", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241323", + "type": "PAYMENT", + "createdOn": "2019-05-31T20:59:58", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "77.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "V4U2WdYWmxnm0pr3GyjO04t83MxrfXDq", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241322", + "type": "PAYMENT", + "createdOn": "2019-05-31T20:59:57", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "6.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "8beVx1bgJvwCUd5D2oGjC8ncSo6y7Nkk", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241321", + "type": "PAYMENT", + "createdOn": "2019-05-04T08:31:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "14.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "lLw5Rk0C7PxbFeHRqJ1k8j17KIjqh4bO", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241320", + "type": "PAYMENT", + "createdOn": "2019-05-04T08:31:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "54.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "uS7EsR8xs1EMAnwjKBbJSE60ULI3s33L", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241319", + "type": "PAYMENT", + "createdOn": "2019-05-04T08:31:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "27.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "1MPa0sDeuWr8P7Iy2pQs4Jv7yUF02SP4", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241318", + "type": "PAYMENT", + "createdOn": "2019-05-04T03:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "8.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "UL2PeLYK2VsOLtA6CTatkoSKTP7TbNXu", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241317", + "type": "PAYMENT", + "createdOn": "2019-05-04T03:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "18.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "qOdsFgE7nnXB0lAu6x5NYd7g3UPVaVLE", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241316", + "type": "PAYMENT", + "createdOn": "2019-05-04T03:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "68.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "xvGWbxlrJUfOUt4yaeUXrpkvnOPc1nOr", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241315", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-04-18T23:25:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-070124d6-778a-4886-95d9-c2e179533a42", + "amount": "78.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "********5888", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241314", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-04-18T23:25:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-070124d6-778a-4886-95d9-c2e179533a42", + "amount": "10.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "********5888", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241313", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-04-18T23:25:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-070124d6-778a-4886-95d9-c2e179533a42", + "amount": "33.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "********5888", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241312", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-04-18T22:25:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-070124d6-778a-4886-95d9-c2e179533a42", + "amount": "46.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "********5888", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241311", + "type": "PAYMENT", + "createdOn": "2019-04-18T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "22.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "Ffib6Cr4a1amY8NCsBIpbg055Gn5Twgl", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241310", + "type": "PAYMENT", + "createdOn": "2019-04-18T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "68.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "bf0W6uPSWlbCw4C4g5IknEuIxP6KArxg", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=0&limit=20&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "next" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=20&limit=20&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "last" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=30&limit=20&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/receipt_list_paged_second_response.json b/receipt/src/test/resources/receipt_list_paged_second_response.json new file mode 100644 index 000000000..ea5ff7d8f --- /dev/null +++ b/receipt/src/test/resources/receipt_list_paged_second_response.json @@ -0,0 +1,202 @@ +{ + "count": 50, + "offset": 20, + "limit": 10, + "data": [ + { + "journalId": "55241309", + "type": "PAYMENT", + "createdOn": "2019-04-01T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "31.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "6gxTXpwcubH3fVRtFdQNurWOyUW1HkVX", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241308", + "type": "PAYMENT", + "createdOn": "2019-04-01T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "86.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "S1qT2lRll6L30mC0DFj7KcVe3mWoKDQB", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241307", + "type": "PAYMENT", + "createdOn": "2019-04-01T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "71.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "HtMITxyTfeCcSdhLWsQT5qkGjpucotrF", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241306", + "type": "PAYMENT", + "createdOn": "2019-04-01T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "51.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "khPj2gCEvgLE3DbMgIP3FrCFrdQwBltv", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241305", + "type": "PAYMENT", + "createdOn": "2019-04-01T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "44.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "3pqvOo05oV0uhDl27f2Qqm73jYDWNwK8", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241304", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-03-11T22:25:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-070124d6-778a-4886-95d9-c2e179533a42", + "amount": "60.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "********5888", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241303", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-03-11T22:25:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-070124d6-778a-4886-95d9-c2e179533a42", + "amount": "86.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "********5888", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241302", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-03-11T22:25:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-070124d6-778a-4886-95d9-c2e179533a42", + "amount": "74.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "********5888", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241301", + "type": "PAYMENT", + "createdOn": "2019-03-11T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "27.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "E1PCxrtc6o3UUGck3wGBWIevYgaMcIrR", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241300", + "type": "PAYMENT", + "createdOn": "2019-03-05T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "33.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "gyHQFLHOTH540eDlysJsSVPOJdSOSHRl", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=20&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "next" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=30&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "previous" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=10&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "first" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=0&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "last" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=40&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/receipt_list_paged_third_response.json b/receipt/src/test/resources/receipt_list_paged_third_response.json new file mode 100644 index 000000000..80b92d304 --- /dev/null +++ b/receipt/src/test/resources/receipt_list_paged_third_response.json @@ -0,0 +1,201 @@ +{ + "count": 50, + "offset": 30, + "limit": 10, + "data": [ + { + "journalId": "55241299", + "type": "PAYMENT", + "createdOn": "2019-03-05T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "1.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "UlwCsRXTdgrdFUuRTPg636Mbvn8XRGjs", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241298", + "type": "PAYMENT", + "createdOn": "2019-03-05T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "13.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "tfM0IjyVMBRGqmsD1dEO3Fy8rK2QUoSm", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241297", + "type": "PAYMENT", + "createdOn": "2019-03-05T22:25:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "4.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "HnttPuohg4cnUbfMJ6vlhcELeRhWwOhT", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241296", + "type": "PAYMENT", + "createdOn": "2019-02-05T12:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "27.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "itps4wsLu1ifsYHBEmD2g5ti185lEEjr", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241295", + "type": "PAYMENT", + "createdOn": "2019-02-05T12:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "77.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "CRRWrHBQKPBui4nfsDmXnohiaFheOp5l", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241294", + "type": "PAYMENT", + "createdOn": "2019-02-05T12:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "71.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "VYHB8eQswywLoCBDgesOwfqh5T55b3mB", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241293", + "type": "PAYMENT", + "createdOn": "2019-02-05T12:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "72.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "QDLwuItkjGNPVwQNOfiLrjeJpDxmEiWt", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241292", + "type": "PAYMENT", + "createdOn": "2019-02-05T12:29:08", + "entry": "CREDIT", + "sourceToken": "act-68adaba2-42f4-4f0f-8670-81c09f319a12", + "destinationToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "amount": "37.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "N6gwhx1BhxXs5ug6bH3xXWXB6p7gixT4", + "notes": "ABC1", + "payeeName": "Brendan Zachery" + } + }, + { + "journalId": "55241291", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-01-05T20:29:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-cc13b0b0-5f4b-4c99-baed-eb16c8952f46", + "amount": "35.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "******9129", + "bankAccountPurpose": "SAVINGS" + } + }, + { + "journalId": "55241290", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-01-05T20:29:08", + "entry": "DEBIT", + "sourceToken": "usr-02d381d3-bf7e-43fe-9d00-02e26b28df57", + "destinationToken": "trm-cc13b0b0-5f4b-4c99-baed-eb16c8952f46", + "amount": "22.00", + "fee": "2.00", + "currency": "USD", + "details": { + "payeeName": "Brendan Zachery", + "branchId": "021000021", + "bankAccountId": "******9129", + "bankAccountPurpose": "SAVINGS" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=30&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "next" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=40&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "previous" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=20&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "first" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=0&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + }, + { + "params": { + "rel": "last" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-02d381d3-bf7e-43fe-9d00-02e26b28df57/receipts?offset=40&limit=10&sortBy=-createdOn&createdAfter=2018-06-10T13%3A29%3A49" + } + ] +} \ No newline at end of file From 18ee56e98c97ec8b3c4d74cb521bcb3ab1b9c26d Mon Sep 17 00:00:00 2001 From: Anna <48258136+azakrevska-epam@users.noreply.github.com> Date: Fri, 14 Jun 2019 00:49:08 +0300 Subject: [PATCH 015/177] HW-53463, HW-53464. Updated createTransferMethod(Wire Account) and tests (#38) --- .../TransferMethodRepositoryImpl.java | 3 + .../AddTransferMethodFragment.java | 8 +++ .../TransferMethodRepositoryImplTest.java | 71 +++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java index 902971023..17aab2028 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java @@ -22,6 +22,7 @@ import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.WIRE_ACCOUNT; import android.os.Handler; @@ -54,6 +55,7 @@ public void createTransferMethod(@NonNull final HyperwalletTransferMethod transf LoadTransferMethodCallback callback) { switch (transferMethod.getField(TYPE)) { case BANK_ACCOUNT: + case WIRE_ACCOUNT: createBankAccount(transferMethod, callback); break; case BANK_CARD: @@ -96,6 +98,7 @@ public void deactivateTransferMethod(@NonNull final HyperwalletTransferMethod tr @NonNull final DeactivateTransferMethodCallback callback) { switch (transferMethod.getField(TYPE)) { case BANK_ACCOUNT: + case WIRE_ACCOUNT: deactivateBankAccount(transferMethod, callback); break; case BANK_CARD: diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java index 2fb5203bc..53e290aa9 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java @@ -23,6 +23,7 @@ import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.WIRE_ACCOUNT; import android.app.Activity; import android.content.Context; @@ -509,6 +510,13 @@ private void triggerSubmit() { .transferMethodCurrency(mCurrency) .build(); break; + case WIRE_ACCOUNT: + mTransferMethod = new HyperwalletBankAccount.Builder() + .transferMethodCountry(mCountry) + .transferMethodCurrency(mCurrency) + .transferMethodType(WIRE_ACCOUNT) + .build(); + break; default: mTransferMethod = new HyperwalletTransferMethod(); mTransferMethod.setField(TRANSFER_METHOD_COUNTRY, mCountry); diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java index 334ad2044..59c3d3ee9 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java @@ -558,4 +558,75 @@ public Object answer(InvocationOnMock invocation) { // assert assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(returnedError)); } + + @Test + public void testCreateTransferMethod_wireAccountWithSuccess() { + HyperwalletBankAccount bankAccount = new HyperwalletBankAccount + .Builder("US", "USD", "1411413412") + .transferMethodType(HyperwalletTransferMethod.TransferMethodTypes.WIRE_ACCOUNT) + .build(); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + HyperwalletBankAccount returnedBank = new HyperwalletBankAccount + .Builder("US", "USD", "1411413412") + .bankName("Mock Bank Response") + .transferMethodType(HyperwalletTransferMethod.TransferMethodTypes.WIRE_ACCOUNT) + .build(); + listener.onSuccess(returnedBank); + return listener; + } + }).when(mHyperwallet).createBankAccount(any(HyperwalletBankAccount.class), + ArgumentMatchers.>any()); + + // test + mTransferMethodRepository.createTransferMethod(bankAccount, mLoadTransferMethodCallback); + + verify(mLoadTransferMethodCallback).onTransferMethodLoaded(mBankAccountArgumentCaptor.capture()); + verify(mLoadTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); + + HyperwalletBankAccount transferMethod = mBankAccountArgumentCaptor.getValue(); + assertThat(transferMethod, is(notNullValue())); + assertThat(transferMethod.getField(TYPE), is(HyperwalletTransferMethod.TransferMethodTypes.WIRE_ACCOUNT)); + assertThat(transferMethod.getField(BANK_NAME), is("Mock Bank Response")); + assertThat(transferMethod.getField(TRANSFER_METHOD_COUNTRY), is("US")); + assertThat(transferMethod.getField(TRANSFER_METHOD_CURRENCY), is("USD")); + assertThat(transferMethod.getField(BANK_ACCOUNT_ID), is("1411413412")); + } + + @Test + public void testDeactivateTransferMethod_wireAccountWithSuccess() { + HyperwalletBankAccount bankAccount = new HyperwalletBankAccount + .Builder("CA", "CAD", "3423423432") + .transferMethodType(HyperwalletTransferMethod.TransferMethodTypes.WIRE_ACCOUNT) + .token("trm-123") + .build(); + bankAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletStatusTransition statusTransition = new HyperwalletStatusTransition(DE_ACTIVATED); + statusTransition.setNotes("Closing this account."); + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onSuccess(statusTransition); + return listener; + } + }).when(mHyperwallet).deactivateBankAccount(anyString(), ArgumentMatchers.isNull(), + ArgumentMatchers.>any()); + + // test + mTransferMethodRepository.deactivateTransferMethod(bankAccount, mDeactivateTransferMethodCallback); + + verify(mDeactivateTransferMethodCallback).onTransferMethodDeactivated( + mStatusTransitionArgumentCaptor.capture()); + verify(mDeactivateTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); + + HyperwalletStatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); + assertThat(statusTransition, is(notNullValue())); + assertThat(statusTransition.getTransition(), is(DE_ACTIVATED)); + assertThat(statusTransition.getNotes(), is("Closing this account.")); + } + } \ No newline at end of file From 35ef347a12a58eee1350f3aba92929a4d4b18613 Mon Sep 17 00:00:00 2001 From: vshcherbyna-epam <48257687+vshcherbyna-epam@users.noreply.github.com> Date: Sat, 15 Jun 2019 01:08:21 +0300 Subject: [PATCH 016/177] HW-53384: Update UI group id (#40) * HW-53384: Update UI group id --- README.md | 2 +- build.gradle | 2 +- common/build.gradle | 2 +- common/src/main/AndroidManifest.xml | 2 +- .../{ => ui}/common/util/DateUtils.java | 2 +- .../common/util/EspressoIdlingResource.java | 2 +- .../view/HorizontalDividerItemDecorator.java | 4 +- .../error/DefaultErrorDialogFragment.java | 4 +- .../DefaultErrorDialogFragmentContract.java | 2 +- .../DefaultErrorDialogFragmentPresenter.java | 2 +- .../view/error/OnNetworkErrorCallback.java | 2 +- .../{ => ui}/common/viewmodel/Event.java | 2 +- .../{ => ui}/common/util/DateUtilsTest.java | 2 +- ...faultErrorDialogFragmentPresenterTest.java | 4 +- receipt/build.gradle | 4 +- receipt/src/androidTest/AndroidManifest.xml | 2 +- .../HyperwalletExternalResourceManager.java | 73 ------- .../rule/HyperwalletMockWebServer.java | 115 ----------- .../{ => ui}/receipt/ListReceiptsTest.java | 20 +- .../android/util/EspressoUtils.java | 187 ------------------ .../android/util/NestedScrollToAction.java | 41 ---- .../util/RecyclerViewCountAssertion.java | 30 --- .../util/TestAuthenticationProvider.java | 51 ----- receipt/src/main/AndroidManifest.xml | 2 +- .../receipt/repository/ReceiptDataSource.java | 4 +- .../repository/ReceiptDataSourceFactory.java | 2 +- .../receipt/repository/ReceiptRepository.java | 4 +- .../repository/ReceiptRepositoryFactory.java | 2 +- .../repository/ReceiptRepositoryImpl.java | 4 +- .../receipt/view/ListReceiptActivity.java | 14 +- .../receipt/view/ListReceiptFragment.java | 8 +- .../view/ReceiptItemDividerDecorator.java | 4 +- .../viewmodel/ListReceiptViewModel.java | 6 +- .../ReceiptDataSourceFactoryTest.java | 2 +- .../repository/ReceiptDataSourceTest.java | 2 +- .../ReceiptRepositoryFactoryTest.java | 2 +- .../HyperwalletExternalResourceManager.java | 0 ui/build.gradle | 4 +- ui/src/androidTest/AndroidManifest.xml | 2 +- ...yperwalletInstrumentedTestApplication.java | 31 --- ...yperwalletInstrumentedTestApplication.java | 2 +- .../HyperwalletExternalResourceManager.java | 2 +- .../rule/HyperwalletMockWebServer.java | 2 +- .../AddTransferMethodTest.java | 19 +- .../transfermethod}/BankAccountTest.java | 25 ++- .../transfermethod}/BankCardTest.java | 21 +- .../ListTransferMethodTest.java | 17 +- .../ui => ui/transfermethod}/PayPalTest.java | 21 +- .../SelectTransferMethodTest.java | 19 +- .../android/{ => ui}/util/EspressoUtils.java | 2 +- .../{ => ui}/util/NestedScrollToAction.java | 2 +- .../util/RecyclerViewCountAssertion.java | 2 +- .../util/TestAuthenticationProvider.java | 2 +- ui/src/main/AndroidManifest.xml | 2 +- .../hyperwallet/android/ui/HyperwalletUi.java | 2 +- ...sferMethodConfigurationRepositoryImpl.java | 3 +- .../AddTransferMethodActivity.java | 6 +- .../AddTransferMethodFragment.java | 2 +- .../ui/transfermethod/FeeFormatter.java | 2 +- .../ListTransferMethodActivity.java | 6 +- .../ListTransferMethodFragment.java | 4 +- .../SelectTransferMethodActivity.java | 6 +- .../SelectTransferMethodFragment.java | 4 +- ...thodConfirmDeactivationDialogFragment.java | 2 +- .../transfermethod/TransferMethodUtils.java | 2 +- .../view/CountrySelectionDialogFragment.java | 2 +- .../view/CurrencySelectionDialogFragment.java | 2 +- .../ui/view/WidgetDateDialogFragment.java | 2 +- .../view/WidgetSelectionDialogFragment.java | 2 +- .../android/ui/view/widget/DateWidget.java | 2 +- .../ui/view/widget/DefaultAccountWidget.java | 2 +- .../ui/view/widget/ExpiryDateWidget.java | 2 +- .../android/ui/view/widget/NumberWidget.java | 2 +- .../android/ui/view/widget/PhoneWidget.java | 2 +- .../ui/view/widget/SelectionWidget.java | 2 +- .../android/ui/view/widget/TextWidget.java | 2 +- ui/src/main/res/values/strings.xml | 2 +- .../ui/transfermethod/FeeFormatterTest.java | 2 +- .../TransferMethodUtilsTest.java | 2 +- 79 files changed, 160 insertions(+), 695 deletions(-) rename common/src/main/java/com/hyperwallet/android/{ => ui}/common/util/DateUtils.java (99%) rename common/src/main/java/com/hyperwallet/android/{ => ui}/common/util/EspressoIdlingResource.java (92%) rename common/src/main/java/com/hyperwallet/android/{ => ui}/common/view/HorizontalDividerItemDecorator.java (98%) rename common/src/main/java/com/hyperwallet/android/{ => ui}/common/view/error/DefaultErrorDialogFragment.java (98%) rename common/src/main/java/com/hyperwallet/android/{ => ui}/common/view/error/DefaultErrorDialogFragmentContract.java (96%) rename common/src/main/java/com/hyperwallet/android/{ => ui}/common/view/error/DefaultErrorDialogFragmentPresenter.java (98%) rename common/src/main/java/com/hyperwallet/android/{ => ui}/common/view/error/OnNetworkErrorCallback.java (82%) rename common/src/main/java/com/hyperwallet/android/{ => ui}/common/viewmodel/Event.java (97%) rename common/src/test/java/com/hyperwallet/android/{ => ui}/common/util/DateUtilsTest.java (97%) rename common/src/test/java/com/hyperwallet/android/{ => ui}/common/view/error/DefaultErrorDialogFragmentPresenterTest.java (96%) delete mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java delete mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java rename receipt/src/androidTest/java/com/hyperwallet/android/{ => ui}/receipt/ListReceiptsTest.java (94%) delete mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java delete mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java delete mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java delete mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java rename receipt/src/main/java/com/hyperwallet/android/{ => ui}/receipt/repository/ReceiptDataSource.java (98%) rename receipt/src/main/java/com/hyperwallet/android/{ => ui}/receipt/repository/ReceiptDataSourceFactory.java (97%) rename receipt/src/main/java/com/hyperwallet/android/{ => ui}/receipt/repository/ReceiptRepository.java (94%) rename receipt/src/main/java/com/hyperwallet/android/{ => ui}/receipt/repository/ReceiptRepositoryFactory.java (97%) rename receipt/src/main/java/com/hyperwallet/android/{ => ui}/receipt/repository/ReceiptRepositoryImpl.java (96%) rename receipt/src/main/java/com/hyperwallet/android/{ => ui}/receipt/view/ListReceiptActivity.java (91%) rename receipt/src/main/java/com/hyperwallet/android/{ => ui}/receipt/view/ListReceiptFragment.java (98%) rename receipt/src/main/java/com/hyperwallet/android/{ => ui}/receipt/view/ReceiptItemDividerDecorator.java (97%) rename receipt/src/main/java/com/hyperwallet/android/{ => ui}/receipt/viewmodel/ListReceiptViewModel.java (95%) rename receipt/src/test/java/com/hyperwallet/android/{ => ui}/receipt/repository/ReceiptDataSourceFactoryTest.java (95%) rename receipt/src/test/java/com/hyperwallet/android/{ => ui}/receipt/repository/ReceiptDataSourceTest.java (99%) rename receipt/src/test/java/com/hyperwallet/android/{ => ui}/receipt/repository/ReceiptRepositoryFactoryTest.java (96%) rename receipt/src/test/java/com/hyperwallet/android/{ => ui}/rule/HyperwalletExternalResourceManager.java (100%) delete mode 100644 ui/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java rename {receipt/src/androidTest/java/com/hyperwallet/android => ui/src/androidTest/java/com/hyperwallet/android/ui}/HyperwalletInstrumentedTestApplication.java (95%) rename ui/src/androidTest/java/com/hyperwallet/android/{ => ui}/rule/HyperwalletExternalResourceManager.java (98%) rename ui/src/androidTest/java/com/hyperwallet/android/{ => ui}/rule/HyperwalletMockWebServer.java (98%) rename ui/src/androidTest/java/com/hyperwallet/android/{transfermethod/ui => ui/transfermethod}/AddTransferMethodTest.java (93%) rename ui/src/androidTest/java/com/hyperwallet/android/{transfermethod/ui => ui/transfermethod}/BankAccountTest.java (96%) rename ui/src/androidTest/java/com/hyperwallet/android/{transfermethod/ui => ui/transfermethod}/BankCardTest.java (95%) rename ui/src/androidTest/java/com/hyperwallet/android/{transfermethod/ui => ui/transfermethod}/ListTransferMethodTest.java (97%) rename ui/src/androidTest/java/com/hyperwallet/android/{transfermethod/ui => ui/transfermethod}/PayPalTest.java (93%) rename ui/src/androidTest/java/com/hyperwallet/android/{transfermethod/ui => ui/transfermethod}/SelectTransferMethodTest.java (97%) rename ui/src/androidTest/java/com/hyperwallet/android/{ => ui}/util/EspressoUtils.java (99%) rename ui/src/androidTest/java/com/hyperwallet/android/{ => ui}/util/NestedScrollToAction.java (96%) rename ui/src/androidTest/java/com/hyperwallet/android/{ => ui}/util/RecyclerViewCountAssertion.java (95%) rename ui/src/androidTest/java/com/hyperwallet/android/{ => ui}/util/TestAuthenticationProvider.java (97%) diff --git a/README.md b/README.md index 3923e8130..96ba8f126 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Note that this SDK is geared towards those who need both backend data and UI fea To install Hyperwallet UI SDK, you just need to add the dependency into your build.gradle file in Android Studio (or Gradle). For example: ```bash -api 'com.hyperwallet.android:ui-sdk:1.0.0-beta02' +api 'com.hyperwallet.android.ui:ui-sdk:1.0.0-beta02' ``` ## Initialization diff --git a/build.gradle b/build.gradle index 4cfcc4791..baab4fd0d 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ allprojects { subprojects { ext { - hyperwalletGroupId = 'com.hyperwallet.android' + hyperwalletGroupId = 'com.hyperwallet.android.ui' compileVersion = 28 minVersion = 21 diff --git a/common/build.gradle b/common/build.gradle index e4df818b5..cf60c3f49 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -81,7 +81,7 @@ sonarqube { properties { def libraries = project.android.sdkDirectory.getPath() + "/platforms/android-28/android.jar" property "sonar.sources", "src/main/java" - property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android" + property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android/ui" property "sonar.libraries", libraries property "sonar.projectName", "android-ui-sdk-common" } diff --git a/common/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml index 72af9106f..414a3f924 100644 --- a/common/src/main/AndroidManifest.xml +++ b/common/src/main/AndroidManifest.xml @@ -1,2 +1,2 @@ + package="com.hyperwallet.android.ui.common"/> diff --git a/common/src/main/java/com/hyperwallet/android/common/util/DateUtils.java b/common/src/main/java/com/hyperwallet/android/ui/common/util/DateUtils.java similarity index 99% rename from common/src/main/java/com/hyperwallet/android/common/util/DateUtils.java rename to common/src/main/java/com/hyperwallet/android/ui/common/util/DateUtils.java index 7fd65e5aa..56ce6cc88 100644 --- a/common/src/main/java/com/hyperwallet/android/common/util/DateUtils.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/util/DateUtils.java @@ -14,7 +14,7 @@ * 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.common.util; +package com.hyperwallet.android.ui.common.util; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; diff --git a/common/src/main/java/com/hyperwallet/android/common/util/EspressoIdlingResource.java b/common/src/main/java/com/hyperwallet/android/ui/common/util/EspressoIdlingResource.java similarity index 92% rename from common/src/main/java/com/hyperwallet/android/common/util/EspressoIdlingResource.java rename to common/src/main/java/com/hyperwallet/android/ui/common/util/EspressoIdlingResource.java index 92e6cf3a4..56c870127 100644 --- a/common/src/main/java/com/hyperwallet/android/common/util/EspressoIdlingResource.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/util/EspressoIdlingResource.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.common.util; +package com.hyperwallet.android.ui.common.util; import androidx.test.espresso.IdlingResource; import androidx.test.espresso.idling.CountingIdlingResource; diff --git a/common/src/main/java/com/hyperwallet/android/common/view/HorizontalDividerItemDecorator.java b/common/src/main/java/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.java similarity index 98% rename from common/src/main/java/com/hyperwallet/android/common/view/HorizontalDividerItemDecorator.java rename to common/src/main/java/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.java index 3e9d3777f..86d294933 100644 --- a/common/src/main/java/com/hyperwallet/android/common/view/HorizontalDividerItemDecorator.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.java @@ -14,7 +14,7 @@ * 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.common.view; +package com.hyperwallet.android.ui.common.view; import android.content.Context; import android.graphics.Canvas; @@ -26,7 +26,7 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; -import com.hyperwallet.android.common.R; +import com.hyperwallet.android.ui.common.R; public class HorizontalDividerItemDecorator extends RecyclerView.ItemDecoration { diff --git a/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragment.java b/common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.java similarity index 98% rename from common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragment.java rename to common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.java index b3ea55029..17f2db87d 100644 --- a/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragment.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.java @@ -14,7 +14,7 @@ * 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.common.view.error; +package com.hyperwallet.android.ui.common.view.error; import static com.hyperwallet.android.ExceptionMapper.EC_AUTHENTICATION_TOKEN_PROVIDER_EXCEPTION; import static com.hyperwallet.android.ExceptionMapper.EC_IO_EXCEPTION; @@ -33,8 +33,8 @@ import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentManager; -import com.hyperwallet.android.common.R; import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.ui.common.R; import java.util.ArrayList; import java.util.List; diff --git a/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentContract.java b/common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentContract.java similarity index 96% rename from common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentContract.java rename to common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentContract.java index 6fd3db51c..2cfc0e219 100644 --- a/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentContract.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentContract.java @@ -14,7 +14,7 @@ * 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.common.view.error; +package com.hyperwallet.android.ui.common.view.error; import android.content.res.Resources; diff --git a/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenter.java b/common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenter.java similarity index 98% rename from common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenter.java rename to common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenter.java index b9f493359..080209765 100644 --- a/common/src/main/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenter.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenter.java @@ -14,7 +14,7 @@ * 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.common.view.error; +package com.hyperwallet.android.ui.common.view.error; import static com.hyperwallet.android.ExceptionMapper.EC_AUTHENTICATION_TOKEN_PROVIDER_EXCEPTION; import static com.hyperwallet.android.ExceptionMapper.EC_IO_EXCEPTION; diff --git a/common/src/main/java/com/hyperwallet/android/common/view/error/OnNetworkErrorCallback.java b/common/src/main/java/com/hyperwallet/android/ui/common/view/error/OnNetworkErrorCallback.java similarity index 82% rename from common/src/main/java/com/hyperwallet/android/common/view/error/OnNetworkErrorCallback.java rename to common/src/main/java/com/hyperwallet/android/ui/common/view/error/OnNetworkErrorCallback.java index a6822c545..e537157a9 100644 --- a/common/src/main/java/com/hyperwallet/android/common/view/error/OnNetworkErrorCallback.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/view/error/OnNetworkErrorCallback.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.common.view.error; +package com.hyperwallet.android.ui.common.view.error; import java.util.List; diff --git a/common/src/main/java/com/hyperwallet/android/common/viewmodel/Event.java b/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java similarity index 97% rename from common/src/main/java/com/hyperwallet/android/common/viewmodel/Event.java rename to common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java index a07aab0e1..0914c82f5 100644 --- a/common/src/main/java/com/hyperwallet/android/common/viewmodel/Event.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java @@ -14,7 +14,7 @@ * 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.common.viewmodel; +package com.hyperwallet.android.ui.common.viewmodel; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/common/src/test/java/com/hyperwallet/android/common/util/DateUtilsTest.java b/common/src/test/java/com/hyperwallet/android/ui/common/util/DateUtilsTest.java similarity index 97% rename from common/src/test/java/com/hyperwallet/android/common/util/DateUtilsTest.java rename to common/src/test/java/com/hyperwallet/android/ui/common/util/DateUtilsTest.java index 27102325b..4b599078b 100644 --- a/common/src/test/java/com/hyperwallet/android/common/util/DateUtilsTest.java +++ b/common/src/test/java/com/hyperwallet/android/ui/common/util/DateUtilsTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.common.util; +package com.hyperwallet.android.ui.common.util; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; diff --git a/common/src/test/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenterTest.java b/common/src/test/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenterTest.java similarity index 96% rename from common/src/test/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenterTest.java rename to common/src/test/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenterTest.java index aa3848d07..39eb47085 100644 --- a/common/src/test/java/com/hyperwallet/android/common/view/error/DefaultErrorDialogFragmentPresenterTest.java +++ b/common/src/test/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenterTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.common.view.error; +package com.hyperwallet.android.ui.common.view.error; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -15,8 +15,8 @@ import android.content.res.Resources; -import com.hyperwallet.android.common.R; import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.ui.common.R; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/receipt/build.gradle b/receipt/build.gradle index 6aa8d9d42..03133faa3 100644 --- a/receipt/build.gradle +++ b/receipt/build.gradle @@ -60,7 +60,7 @@ publishing { configurations.implementation.allDependencies.each { def dependencyNode = dependenciesNode.appendNode('dependency') if (it.group == "hyperwallet-android-ui-sdk") { - dependencyNode.appendNode('groupId', "com.hyperwallet.android") + dependencyNode.appendNode('groupId', "com.hyperwallet.android.ui") } else { dependencyNode.appendNode('groupId', it.group) } @@ -104,7 +104,7 @@ sonarqube { properties { def libraries = project.android.sdkDirectory.getPath() + "/platforms/android-28/android.jar" property "sonar.sources", "src/main/java" - property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android" + property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android/ui" property "sonar.libraries", libraries property "sonar.projectName", "android-ui-sdk-receipt" } diff --git a/receipt/src/androidTest/AndroidManifest.xml b/receipt/src/androidTest/AndroidManifest.xml index 8495adb45..eb1e37113 100644 --- a/receipt/src/androidTest/AndroidManifest.xml +++ b/receipt/src/androidTest/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="com.hyperwallet.android.ui.receipt.test"> diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java b/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java deleted file mode 100644 index e7e546063..000000000 --- a/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.hyperwallet.android.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class HyperwalletExternalResourceManager extends TestWatcher { - - private static final String EMPTY = ""; - private ClassLoader classLoader; - private Logger logger; - - @Override - protected void starting(Description description) { - super.starting(description); - classLoader = description.getTestClass().getClassLoader(); - logger = Logger.getLogger(description.getTestClass().getName()); - } - - public String getResourceContent(final String resourceName) { - if (resourceName == null) { - throw new IllegalArgumentException("Parameter resourceName cannot be null"); - } - - return getContent(resourceName); - } - - private String getContent(final String resourceName) { - - URL resource = classLoader.getResource(resourceName); - InputStream inputStream = null; - Writer writer = new StringWriter(); - String resourceContent = EMPTY; - if (resource != null) { - try { - inputStream = resource.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); - String line = reader.readLine(); - while (line != null) { - writer.write(line); - line = reader.readLine(); - } - resourceContent = writer.toString(); - - } catch (Exception e) { - logger.log(Level.WARNING, "There was an error loading an external resource", e); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "There was an error closing input stream", e); - } - try { - writer.close(); - } catch (IOException e) { - logger.log(Level.SEVERE, "There was an error closing writer", e); - } - } - } - return resourceContent; - } -} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java b/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java deleted file mode 100644 index 9f42f6128..000000000 --- a/receipt/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.hyperwallet.android.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.IOException; -import java.net.HttpURLConnection; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; - -public final class HyperwalletMockWebServer extends TestWatcher { - - private MockWebServer mServer; - private int port; - - public HyperwalletMockWebServer(int port) { - this.port = port; - } - - @Override - protected void starting(Description description) { - super.starting(description); - mServer = new MockWebServer(); - try { - mServer.start(port); - } catch (IOException e) { - throw new IllegalStateException("Unable to start mock server", e); - } - } - - @Override - protected void finished(Description description) { - super.finished(description); - try { - mServer.shutdown(); - mServer.close(); - } catch (IOException e) { - throw new IllegalStateException("Un error occurred when shutting down mock server", e); - } - } - - public HyperwalletMockResponse mockResponse() { - return new Builder(mServer).build(); - } - - public MockWebServer getServer() { - return mServer; - } - - public static class HyperwalletMockResponse { - - private String path; - private String body; - private int httpResponseCode; - private Builder builder; - - HyperwalletMockResponse(Builder builder) { - this.path = builder.path; - this.httpResponseCode = builder.responseCode; - this.body = builder.body; - this.builder = builder; - } - - public HyperwalletMockResponse withHttpResponseCode(final int code) { - builder.responseCode(code); - return builder.build(); - } - - public HyperwalletMockResponse withBody(final String body) { - builder.body(body); - return builder.build(); - } - - public void mock() { - mockRequest(); - } - - private String mockRequest() { - builder.server.enqueue(new MockResponse().setResponseCode(httpResponseCode).setBody(body)); - return builder.server.url(path).toString(); - } - - } - - private static class Builder { - - private String path; - private String body; - private int responseCode; - private MockWebServer server; - - - Builder(final MockWebServer server) { - this.path = ""; - this.responseCode = HttpURLConnection.HTTP_OK; - this.body = ""; - this.server = server; - } - - Builder responseCode(final int code) { - this.responseCode = code; - return this; - } - - Builder body(final String body) { - this.body = body; - return this; - } - - HyperwalletMockResponse build() { - return new HyperwalletMockResponse(this); - } - } -} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java similarity index 94% rename from receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java rename to receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java index 05c0e5c59..b68f3ec04 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/receipt/ListReceiptsTest.java +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.receipt; +package com.hyperwallet.android.ui.receipt; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.assertion.ViewAssertions.matches; @@ -27,10 +27,10 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.receipt.repository.ReceiptRepositoryFactory; -import com.hyperwallet.android.receipt.view.ListReceiptActivity; import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.receipt.repository.ReceiptRepositoryFactory; +import com.hyperwallet.android.ui.receipt.view.ListReceiptActivity; import com.hyperwallet.android.util.RecyclerViewCountAssertion; import com.hyperwallet.android.util.TestAuthenticationProvider; @@ -86,7 +86,7 @@ public void testListReceipts_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)) .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(0, - hasDescendant(withText(com.hyperwallet.android.receipt.R.string.credit))))); + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.credit))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(0, hasDescendant(withText("Payment"))))); onView(withId(R.id.list_receipts)).check( @@ -96,7 +96,7 @@ public void testListReceipts_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("USD"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(1, - hasDescendant(withText(com.hyperwallet.android.receipt.R.string.credit))))); + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.credit))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(1, hasDescendant(withText("Payment"))))); onView(withId(R.id.list_receipts)).check( @@ -106,7 +106,7 @@ public void testListReceipts_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check(matches(atPosition(1, hasDescendant(withText("CAD"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(2, - hasDescendant(withText(com.hyperwallet.android.receipt.R.string.debit))))); + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.debit))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(2, hasDescendant(withText("Card Activation Fee"))))); onView(withId(R.id.list_receipts)).check( @@ -118,7 +118,7 @@ public void testListReceipts_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)) .check(matches(atPosition(3, hasDescendant(withText("December 2018"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(3, - hasDescendant(withText(com.hyperwallet.android.receipt.R.string.debit))))); + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.debit))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(3, hasDescendant(withText("Card Load"))))); onView(withId(R.id.list_receipts)).check( @@ -147,7 +147,7 @@ public void testListReceipts_displayCreditTransaction() { onView(withId(R.id.list_receipts)) .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(0, - hasDescendant(withText(com.hyperwallet.android.receipt.R.string.credit))))); + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.credit))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(0, hasDescendant(withText(R.string.payment))))); onView(withId(R.id.list_receipts)).check( @@ -176,7 +176,7 @@ public void testListReceipts_displayDebitTransaction() { onView(withId(R.id.list_receipts)) .check(matches(atPosition(0, hasDescendant(withText("May 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(0, - hasDescendant(withText(com.hyperwallet.android.receipt.R.string.debit))))); + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.debit))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(0, hasDescendant(withText(R.string.transfer_to_prepaid_card))))); onView(withId(R.id.list_receipts)).check( @@ -205,7 +205,7 @@ public void testListReceipts_displayUnknownTransactionType() { onView(withId(R.id.list_receipts)) .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(0, - hasDescendant(withText(com.hyperwallet.android.receipt.R.string.credit))))); + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.credit))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(0, hasDescendant(withText(R.string.unknown_type))))); onView(withId(R.id.list_receipts)).check( diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java b/receipt/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java deleted file mode 100644 index 92a711f96..000000000 --- a/receipt/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java +++ /dev/null @@ -1,187 +0,0 @@ -package com.hyperwallet.android.util; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.view.View; -import android.widget.EditText; -import android.widget.ImageView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; -import androidx.test.espresso.ViewAction; -import androidx.test.espresso.action.ViewActions; -import androidx.test.espresso.matcher.BoundedMatcher; - -import com.google.android.material.textfield.TextInputLayout; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -import java.util.Objects; - -public class EspressoUtils { - - public static Matcher withHint(final String expectedHint) { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof TextInputLayout)) { - return false; - } - - String hint = Objects.toString(((TextInputLayout) view).getHint()); - return expectedHint.equals(hint); - } - - @Override - public void describeTo(Description description) { - description.appendText(expectedHint); - } - }; - } - - public static Matcher hasErrorText(final String expectedErrorMessage) { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof TextInputLayout)) { - return false; - } - - String errorMessage = Objects.toString(((TextInputLayout) view).getError()); - return expectedErrorMessage.equals(errorMessage); - } - - @Override - public void describeTo(Description description) { - description.appendText(expectedErrorMessage); - } - }; - } - - public static Matcher hasErrorText(final int resourceId) { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof TextInputLayout)) { - return false; - } - String expectedErrorMessage = view.getResources().getString(resourceId); - String errorMessage = Objects.toString(((TextInputLayout) view).getError()); - - return expectedErrorMessage.equals(errorMessage); - } - - @Override - public void describeTo(Description description) { - } - }; - } - - public static Matcher withDrawable(final int resourceId) { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof ImageView)) { - return false; - } - - Drawable drawable = ((ImageView) view).getDrawable(); - if (drawable == null) { - return false; - } - Drawable expectedDrawable = view.getContext().getResources().getDrawable(resourceId); - - Bitmap bitmap = getBitmap(drawable); - Bitmap expectedBitmap = getBitmap(expectedDrawable); - - return bitmap.sameAs(expectedBitmap); - } - - @Override - public void describeTo(Description description) { - } - }; - } - - public static Matcher atPosition(final int position, @NonNull final Matcher matcher) { - return new BoundedMatcher(RecyclerView.class) { - - @Override - protected boolean matchesSafely(final RecyclerView view) { - RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(position); - - if (viewHolder == null) { - return false; - } - - return matcher.matches(viewHolder.itemView); - } - - @Override - public void describeTo(Description description) { - description.appendText("has item at position " + position + ": "); - matcher.describeTo(description); - } - }; - } - - public static ViewAction nestedScrollTo() { - return ViewActions.actionWithAssertions(new NestedScrollToAction()); - } - - private static Bitmap getBitmap(Drawable drawable) { - Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - - Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - - return bitmap; - } - - public static Matcher hasNoErrorText() { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof TextInputLayout)) { - return false; - } - return ((TextInputLayout) view).getError() == null; - } - - @Override - public void describeTo(Description description) { - description.appendText("has no error text: "); - } - }; - } - - public static Matcher hasEmptyText() { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof EditText)) { - return false; - } - String text = ((EditText) view).getText().toString(); - - return text.isEmpty(); - } - - @Override - public void describeTo(Description description) { - } - }; - } -} - diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java b/receipt/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java deleted file mode 100644 index 392867387..000000000 --- a/receipt/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.hyperwallet.android.util; - -import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; -import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; -import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; - -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anyOf; - -import android.view.View; - -import androidx.core.widget.NestedScrollView; -import androidx.test.espresso.UiController; -import androidx.test.espresso.ViewAction; -import androidx.test.espresso.action.ScrollToAction; -import androidx.test.espresso.matcher.ViewMatchers; - -import org.hamcrest.Matcher; - -public class NestedScrollToAction implements ViewAction { - private static final String TAG = ScrollToAction.class.getSimpleName(); - - @SuppressWarnings("unchecked") - @Override - public Matcher getConstraints() { - return allOf( - withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), - isDescendantOfA( - anyOf(isAssignableFrom(NestedScrollView.class)))); - } - - @Override - public void perform(UiController uiController, View view) { - new ScrollToAction().perform(uiController, view); - } - - @Override - public String getDescription() { - return "scroll to"; - } -} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java b/receipt/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java deleted file mode 100644 index bb3aecaff..000000000 --- a/receipt/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.hyperwallet.android.util; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -import android.view.View; - -import androidx.recyclerview.widget.RecyclerView; -import androidx.test.espresso.NoMatchingViewException; -import androidx.test.espresso.ViewAssertion; - -public class RecyclerViewCountAssertion implements ViewAssertion { - private final int mCount; - - public RecyclerViewCountAssertion(int count) { - this.mCount = count; - } - - @Override - public void check(View view, NoMatchingViewException noViewFoundException) { - if (noViewFoundException != null) { - throw noViewFoundException; - } - - RecyclerView recyclerView = (RecyclerView) view; - RecyclerView.Adapter adapter = recyclerView.getAdapter(); - - assertThat(adapter.getItemCount(), is(mCount)); - } -} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java b/receipt/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java deleted file mode 100644 index 686ccbf30..000000000 --- a/receipt/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.hyperwallet.android.util; - -import com.hyperwallet.android.HyperwalletAuthenticationTokenListener; -import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; - -import java.io.IOException; -import java.text.MessageFormat; -import java.util.UUID; - -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; - -public class TestAuthenticationProvider implements HyperwalletAuthenticationTokenProvider { - - public static final MediaType JSON - = MediaType.get("application/json; charset=utf-8"); - private static final String mBaseUrl = "http://localhost:8080/rest/v3/users/{0}/authentication-token"; - private static final String mUserToken = "user_token"; - - @Override - public void retrieveAuthenticationToken(final HyperwalletAuthenticationTokenListener authenticationTokenListener) { - - OkHttpClient client = new OkHttpClient(); - - String payload = "{}"; - String baseUrl = MessageFormat.format(mBaseUrl, mUserToken); - - RequestBody body = RequestBody.create(JSON, payload); - Request request = new Request.Builder() - .url(baseUrl) - .post(body) - .build(); - - client.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(Call call, IOException e) { - authenticationTokenListener.onFailure(UUID.randomUUID(), e.getMessage()); - } - - @Override - public void onResponse(Call call, Response response) throws IOException { - authenticationTokenListener.onSuccess(response.body().string()); - } - }); - } -} diff --git a/receipt/src/main/AndroidManifest.xml b/receipt/src/main/AndroidManifest.xml index 3716721ff..d817501e5 100644 --- a/receipt/src/main/AndroidManifest.xml +++ b/receipt/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ + package="com.hyperwallet.android.ui.receipt"> diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSource.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java similarity index 98% rename from receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSource.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java index 5320214fb..f6e30479b 100644 --- a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSource.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java @@ -14,7 +14,7 @@ * 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.receipt.repository; +package com.hyperwallet.android.ui.receipt.repository; import android.os.Handler; @@ -25,13 +25,13 @@ import androidx.paging.PageKeyedDataSource; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.common.viewmodel.Event; import com.hyperwallet.android.exception.HyperwalletException; import com.hyperwallet.android.listener.HyperwalletListener; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.model.receipt.ReceiptQueryParam; +import com.hyperwallet.android.ui.common.viewmodel.Event; import java.util.Calendar; diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactory.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactory.java similarity index 97% rename from receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactory.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactory.java index a2b81216b..ca3186540 100644 --- a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactory.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactory.java @@ -14,7 +14,7 @@ * 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.receipt.repository; +package com.hyperwallet.android.ui.receipt.repository; import androidx.annotation.NonNull; import androidx.lifecycle.LiveData; diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepository.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepository.java similarity index 94% rename from receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepository.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepository.java index 542d03c89..2db846a4f 100644 --- a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepository.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepository.java @@ -14,14 +14,14 @@ * 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.receipt.repository; +package com.hyperwallet.android.ui.receipt.repository; import androidx.lifecycle.LiveData; import androidx.paging.PagedList; -import com.hyperwallet.android.common.viewmodel.Event; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.viewmodel.Event; /** * Receipt Repository Contract diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactory.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactory.java similarity index 97% rename from receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactory.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactory.java index b096ab7a0..8fc76d7ab 100644 --- a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactory.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactory.java @@ -14,7 +14,7 @@ * 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.receipt.repository; +package com.hyperwallet.android.ui.receipt.repository; /** * {@link ReceiptRepository} factory diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryImpl.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryImpl.java similarity index 96% rename from receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryImpl.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryImpl.java index cde7edd94..74fe8755d 100644 --- a/receipt/src/main/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryImpl.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryImpl.java @@ -14,15 +14,15 @@ * 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.receipt.repository; +package com.hyperwallet.android.ui.receipt.repository; import androidx.lifecycle.LiveData; import androidx.paging.LivePagedListBuilder; import androidx.paging.PagedList; -import com.hyperwallet.android.common.viewmodel.Event; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.viewmodel.Event; /** * {@link ReceiptRepository} implementation diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptActivity.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java similarity index 91% rename from receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptActivity.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java index e7f57c821..6f203949d 100644 --- a/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptActivity.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java @@ -14,7 +14,7 @@ * 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.receipt.view; +package com.hyperwallet.android.ui.receipt.view; import android.content.Intent; import android.os.Bundle; @@ -30,14 +30,14 @@ import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProviders; -import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; -import com.hyperwallet.android.common.view.error.OnNetworkErrorCallback; -import com.hyperwallet.android.common.viewmodel.Event; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletErrors; -import com.hyperwallet.android.receipt.R; -import com.hyperwallet.android.receipt.repository.ReceiptRepositoryFactory; -import com.hyperwallet.android.receipt.viewmodel.ListReceiptViewModel; +import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; +import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.receipt.R; +import com.hyperwallet.android.ui.receipt.repository.ReceiptRepositoryFactory; +import com.hyperwallet.android.ui.receipt.viewmodel.ListReceiptViewModel; import java.util.List; diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptFragment.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java similarity index 98% rename from receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptFragment.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java index ce6f9fd4d..2e2e33cac 100644 --- a/receipt/src/main/java/com/hyperwallet/android/receipt/view/ListReceiptFragment.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java @@ -14,7 +14,7 @@ * 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.receipt.view; +package com.hyperwallet.android.ui.receipt.view; import static com.hyperwallet.android.model.receipt.Receipt.Entries.CREDIT; import static com.hyperwallet.android.model.receipt.Receipt.Entries.DEBIT; @@ -37,10 +37,10 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.hyperwallet.android.common.util.DateUtils; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.receipt.R; -import com.hyperwallet.android.receipt.viewmodel.ListReceiptViewModel; +import com.hyperwallet.android.ui.common.util.DateUtils; +import com.hyperwallet.android.ui.receipt.R; +import com.hyperwallet.android.ui.receipt.viewmodel.ListReceiptViewModel; import java.util.Calendar; import java.util.Locale; diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/view/ReceiptItemDividerDecorator.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptItemDividerDecorator.java similarity index 97% rename from receipt/src/main/java/com/hyperwallet/android/receipt/view/ReceiptItemDividerDecorator.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptItemDividerDecorator.java index c61b22e5d..16f4d51ee 100644 --- a/receipt/src/main/java/com/hyperwallet/android/receipt/view/ReceiptItemDividerDecorator.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptItemDividerDecorator.java @@ -14,7 +14,7 @@ * 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.receipt.view; +package com.hyperwallet.android.ui.receipt.view; import android.content.Context; import android.graphics.Canvas; @@ -25,7 +25,7 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; -import com.hyperwallet.android.common.view.HorizontalDividerItemDecorator; +import com.hyperwallet.android.ui.common.view.HorizontalDividerItemDecorator; public class ReceiptItemDividerDecorator extends HorizontalDividerItemDecorator { diff --git a/receipt/src/main/java/com/hyperwallet/android/receipt/viewmodel/ListReceiptViewModel.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java similarity index 95% rename from receipt/src/main/java/com/hyperwallet/android/receipt/viewmodel/ListReceiptViewModel.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java index 57f41b5c1..264e78974 100644 --- a/receipt/src/main/java/com/hyperwallet/android/receipt/viewmodel/ListReceiptViewModel.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java @@ -14,7 +14,7 @@ * 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.receipt.viewmodel; +package com.hyperwallet.android.ui.receipt.viewmodel; import androidx.annotation.NonNull; import androidx.lifecycle.LiveData; @@ -24,10 +24,10 @@ import androidx.lifecycle.ViewModelProvider; import androidx.paging.PagedList; -import com.hyperwallet.android.common.viewmodel.Event; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.receipt.repository.ReceiptRepository; +import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.receipt.repository.ReceiptRepository; public class ListReceiptViewModel extends ViewModel { diff --git a/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactoryTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactoryTest.java similarity index 95% rename from receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactoryTest.java rename to receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactoryTest.java index cf5c63114..b8a6974f2 100644 --- a/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceFactoryTest.java +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactoryTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.receipt.repository; +package com.hyperwallet.android.ui.receipt.repository; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java similarity index 99% rename from receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceTest.java rename to receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java index d09854710..9cf699e83 100644 --- a/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptDataSourceTest.java +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.receipt.repository; +package com.hyperwallet.android.ui.receipt.repository; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; diff --git a/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactoryTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactoryTest.java similarity index 96% rename from receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactoryTest.java rename to receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactoryTest.java index 3326f2916..714becb62 100644 --- a/receipt/src/test/java/com/hyperwallet/android/receipt/repository/ReceiptRepositoryFactoryTest.java +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactoryTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.receipt.repository; +package com.hyperwallet.android.ui.receipt.repository; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; diff --git a/receipt/src/test/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java b/receipt/src/test/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java similarity index 100% rename from receipt/src/test/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java rename to receipt/src/test/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java diff --git a/ui/build.gradle b/ui/build.gradle index 7d74976ae..bc6fa3a49 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -62,7 +62,7 @@ publishing { configurations.implementation.allDependencies.each { def dependencyNode = dependenciesNode.appendNode('dependency') if (it.group == "hyperwallet-android-ui-sdk") { - dependencyNode.appendNode('groupId', "com.hyperwallet.android") + dependencyNode.appendNode('groupId', "com.hyperwallet.android.ui") } else { dependencyNode.appendNode('groupId', it.group) } @@ -106,7 +106,7 @@ sonarqube { properties { def libraries = project.android.sdkDirectory.getPath() + "/platforms/android-28/android.jar" property "sonar.sources", "src/main/java" - property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android" + property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android/ui" property "sonar.libraries", libraries property "sonar.projectName", "android-ui-sdk" } diff --git a/ui/src/androidTest/AndroidManifest.xml b/ui/src/androidTest/AndroidManifest.xml index 0cd133def..ac7de9735 100644 --- a/ui/src/androidTest/AndroidManifest.xml +++ b/ui/src/androidTest/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="com.hyperwallet.android.ui.test"> diff --git a/ui/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java b/ui/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java deleted file mode 100644 index dfc559d2e..000000000 --- a/ui/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.hyperwallet.android; - - -import android.app.Application; - -import com.squareup.leakcanary.InstrumentationLeakDetector; -import com.squareup.leakcanary.LeakCanary; - -public class HyperwalletInstrumentedTestApplication extends Application { - - @Override - public void onCreate() { - - super.onCreate(); - if (LeakCanary.isInAnalyzerProcess(this)) { - // This process is dedicated to LeakCanary for heap analysis. - // You should not init your app in this process. - return; - } - installLeakCanary(); - } - - - protected void installLeakCanary() { - - InstrumentationLeakDetector.instrumentationRefWatcher(this) - .buildAndInstall(); - - } - -} \ No newline at end of file diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/HyperwalletInstrumentedTestApplication.java similarity index 95% rename from receipt/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/HyperwalletInstrumentedTestApplication.java index dfc559d2e..1e77c01b7 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/HyperwalletInstrumentedTestApplication.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/HyperwalletInstrumentedTestApplication.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android; +package com.hyperwallet.android.ui; import android.app.Application; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java similarity index 98% rename from ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java index e7e546063..0fd013e52 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletExternalResourceManager.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.rule; +package com.hyperwallet.android.ui.rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletMockWebServer.java similarity index 98% rename from ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletMockWebServer.java index 9f42f6128..fd37ac735 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/rule/HyperwalletMockWebServer.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletMockWebServer.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.rule; +package com.hyperwallet.android.ui.rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java similarity index 93% rename from ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java index f8751b9b6..18989446a 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/AddTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.transfermethod.ui; +package com.hyperwallet.android.ui.transfermethod; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; @@ -21,8 +21,8 @@ import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; import static java.net.HttpURLConnection.HTTP_OK; -import static com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment.RESULT_ERROR; -import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment.RESULT_ERROR; +import static com.hyperwallet.android.ui.util.EspressoUtils.nestedScrollTo; import android.app.Instrumentation; import android.content.Intent; @@ -35,14 +35,13 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.common.util.EspressoIdlingResource; -import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; -import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; +import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; -import com.hyperwallet.android.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.util.TestAuthenticationProvider; import org.junit.After; import org.junit.Before; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java similarity index 96% rename from ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java index 5bd2e49dd..45d92c6a7 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankAccountTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.transfermethod.ui; +package com.hyperwallet.android.ui.transfermethod; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; @@ -24,11 +24,11 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount.Purpose.SAVINGS; -import static com.hyperwallet.android.util.EspressoUtils.hasEmptyText; -import static com.hyperwallet.android.util.EspressoUtils.hasErrorText; -import static com.hyperwallet.android.util.EspressoUtils.hasNoErrorText; -import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; -import static com.hyperwallet.android.util.EspressoUtils.withHint; +import static com.hyperwallet.android.ui.util.EspressoUtils.hasEmptyText; +import static com.hyperwallet.android.ui.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.ui.util.EspressoUtils.hasNoErrorText; +import static com.hyperwallet.android.ui.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.util.EspressoUtils.withHint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -45,15 +45,14 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.common.util.EspressoIdlingResource; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; -import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; -import com.hyperwallet.android.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.util.RecyclerViewCountAssertion; +import com.hyperwallet.android.ui.util.TestAuthenticationProvider; import org.junit.After; import org.junit.Before; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java similarity index 95% rename from ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java index f3c15fa11..8f98ffabf 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/BankCardTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.transfermethod.ui; +package com.hyperwallet.android.ui.transfermethod; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; @@ -22,10 +22,10 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.concurrent.TimeUnit.SECONDS; -import static com.hyperwallet.android.util.EspressoUtils.hasEmptyText; -import static com.hyperwallet.android.util.EspressoUtils.hasErrorText; -import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; -import static com.hyperwallet.android.util.EspressoUtils.withHint; +import static com.hyperwallet.android.ui.util.EspressoUtils.hasEmptyText; +import static com.hyperwallet.android.ui.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.ui.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.util.EspressoUtils.withHint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -42,14 +42,13 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.common.util.EspressoIdlingResource; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; -import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; -import com.hyperwallet.android.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.util.TestAuthenticationProvider; import org.junit.After; import org.junit.Before; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/ListTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java similarity index 97% rename from ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/ListTransferMethodTest.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java index 9c7038a6f..3f8412743 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/ListTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.transfermethod.ui; +package com.hyperwallet.android.ui.transfermethod; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; @@ -21,8 +21,8 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.DE_ACTIVATED; -import static com.hyperwallet.android.util.EspressoUtils.atPosition; -import static com.hyperwallet.android.util.EspressoUtils.withDrawable; +import static com.hyperwallet.android.ui.util.EspressoUtils.atPosition; +import static com.hyperwallet.android.ui.util.EspressoUtils.withDrawable; import android.content.BroadcastReceiver; import android.content.Context; @@ -38,14 +38,13 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletStatusTransition; -import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.transfermethod.ListTransferMethodActivity; -import com.hyperwallet.android.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.util.RecyclerViewCountAssertion; +import com.hyperwallet.android.ui.util.TestAuthenticationProvider; import org.hamcrest.Matchers; import org.junit.After; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java similarity index 93% rename from ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java index ec88b9dd0..1bef2a80a 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/PayPalTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.transfermethod.ui; +package com.hyperwallet.android.ui.transfermethod; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; @@ -24,10 +24,10 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.concurrent.TimeUnit.SECONDS; -import static com.hyperwallet.android.util.EspressoUtils.hasEmptyText; -import static com.hyperwallet.android.util.EspressoUtils.hasErrorText; -import static com.hyperwallet.android.util.EspressoUtils.nestedScrollTo; -import static com.hyperwallet.android.util.EspressoUtils.withHint; +import static com.hyperwallet.android.ui.util.EspressoUtils.hasEmptyText; +import static com.hyperwallet.android.ui.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.ui.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.util.EspressoUtils.withHint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -44,14 +44,13 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.common.util.EspressoIdlingResource; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; -import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; -import com.hyperwallet.android.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.util.TestAuthenticationProvider; import org.junit.After; import org.junit.Before; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java similarity index 97% rename from ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java index c644703cd..ad44411c8 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/transfermethod/ui/SelectTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.transfermethod.ui; +package com.hyperwallet.android.ui.transfermethod; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; @@ -29,8 +29,8 @@ import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY; import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE; import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_TYPE; -import static com.hyperwallet.android.util.EspressoUtils.atPosition; -import static com.hyperwallet.android.util.EspressoUtils.withDrawable; +import static com.hyperwallet.android.ui.util.EspressoUtils.atPosition; +import static com.hyperwallet.android.ui.util.EspressoUtils.withDrawable; import android.widget.TextView; @@ -42,14 +42,13 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.common.util.EspressoIdlingResource; -import com.hyperwallet.android.hyperwallet_ui.R; -import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.transfermethod.SelectTransferMethodActivity; -import com.hyperwallet.android.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.util.RecyclerViewCountAssertion; +import com.hyperwallet.android.ui.util.TestAuthenticationProvider; import org.junit.After; import org.junit.Before; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/util/EspressoUtils.java similarity index 99% rename from ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/util/EspressoUtils.java index 92a711f96..72891a832 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/util/EspressoUtils.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/util/EspressoUtils.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.util; +package com.hyperwallet.android.ui.util; import android.graphics.Bitmap; import android.graphics.Canvas; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/util/NestedScrollToAction.java similarity index 96% rename from ui/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/util/NestedScrollToAction.java index 392867387..54f08aed7 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/util/NestedScrollToAction.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/util/NestedScrollToAction.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.util; +package com.hyperwallet.android.ui.util; import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/util/RecyclerViewCountAssertion.java similarity index 95% rename from ui/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/util/RecyclerViewCountAssertion.java index bb3aecaff..e3c7945fd 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/util/RecyclerViewCountAssertion.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/util/RecyclerViewCountAssertion.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.util; +package com.hyperwallet.android.ui.util; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/util/TestAuthenticationProvider.java similarity index 97% rename from ui/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java rename to ui/src/androidTest/java/com/hyperwallet/android/ui/util/TestAuthenticationProvider.java index 686ccbf30..1f8350f8f 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/util/TestAuthenticationProvider.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/util/TestAuthenticationProvider.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.util; +package com.hyperwallet.android.ui.util; import com.hyperwallet.android.HyperwalletAuthenticationTokenListener; import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; diff --git a/ui/src/main/AndroidManifest.xml b/ui/src/main/AndroidManifest.xml index c147fe710..6888120a5 100644 --- a/ui/src/main/AndroidManifest.xml +++ b/ui/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ + package="com.hyperwallet.android.ui"> diff --git a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java index aae63fa7e..b47c1f87d 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java @@ -31,7 +31,7 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; -import com.hyperwallet.android.receipt.view.ListReceiptActivity; +import com.hyperwallet.android.ui.receipt.view.ListReceiptActivity; import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; import com.hyperwallet.android.ui.transfermethod.ListTransferMethodActivity; import com.hyperwallet.android.ui.transfermethod.SelectTransferMethodActivity; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java index 4fe1861a4..a058b61d3 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java @@ -33,7 +33,6 @@ import androidx.annotation.VisibleForTesting; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.common.util.EspressoIdlingResource; import com.hyperwallet.android.exception.HyperwalletException; import com.hyperwallet.android.listener.HyperwalletListener; import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; @@ -41,7 +40,7 @@ import com.hyperwallet.android.model.graphql.keyed.HyperwalletTransferMethodType; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationFieldQuery; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationKeysQuery; -import com.hyperwallet.android.common.util.EspressoIdlingResource; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import java.util.HashMap; import java.util.Map; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java index 4dbd6eb55..9c1fa1d77 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java @@ -28,10 +28,10 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; -import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; -import com.hyperwallet.android.common.view.error.OnNetworkErrorCallback; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; import com.hyperwallet.android.ui.view.WidgetDateDialogFragment; import com.hyperwallet.android.ui.view.WidgetSelectionDialogFragment; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java index 53e290aa9..471f184f5 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java @@ -46,7 +46,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.hyperwallet.android.exception.HyperwalletException; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.graphql.HyperwalletFee; import com.hyperwallet.android.model.graphql.field.HyperwalletField; @@ -56,6 +55,7 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.model.transfermethod.PayPalAccount; import com.hyperwallet.android.ui.HyperwalletLocalBroadcast; +import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.view.WidgetDateDialogFragment; import com.hyperwallet.android.ui.view.WidgetSelectionDialogFragment; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java index 9e0c25358..e073e0a1b 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java @@ -22,8 +22,8 @@ import androidx.annotation.NonNull; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.graphql.HyperwalletFee; +import com.hyperwallet.android.ui.R; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java index 9f3f37654..64ba48309 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java @@ -30,11 +30,11 @@ import androidx.fragment.app.FragmentTransaction; import com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; -import com.hyperwallet.android.common.view.error.OnNetworkErrorCallback; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; import com.hyperwallet.android.ui.view.widget.OneClickListener; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java index d09829047..634bc0af2 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java @@ -48,12 +48,12 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.hyperwallet.android.common.view.HorizontalDividerItemDecorator; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletStatusTransition; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.HyperwalletLocalBroadcast; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.view.HorizontalDividerItemDecorator; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.view.widget.OneClickListener; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodActivity.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodActivity.java index a0582988b..9415590ac 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodActivity.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodActivity.java @@ -31,10 +31,10 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; -import com.hyperwallet.android.common.view.error.DefaultErrorDialogFragment; -import com.hyperwallet.android.common.view.error.OnNetworkErrorCallback; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; import com.hyperwallet.android.ui.view.CountrySelectionDialogFragment; import com.hyperwallet.android.ui.view.CurrencySelectionDialogFragment; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java index 154a2bff0..8c757bb2e 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java @@ -38,9 +38,9 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.hyperwallet.android.common.view.HorizontalDividerItemDecorator; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.view.HorizontalDividerItemDecorator; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.view.CountrySelectionDialogFragment; import com.hyperwallet.android.ui.view.CurrencySelectionDialogFragment; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodConfirmDeactivationDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodConfirmDeactivationDialogFragment.java index 433bfa879..bd9339659 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodConfirmDeactivationDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodConfirmDeactivationDialogFragment.java @@ -27,7 +27,7 @@ import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentManager; -import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.ui.R; public class TransferMethodConfirmDeactivationDialogFragment extends DialogFragment { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java index 87877cddd..127c21818 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java @@ -29,9 +29,9 @@ import androidx.annotation.NonNull; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodType; +import com.hyperwallet.android.ui.R; import java.util.Locale; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java index 828697756..66980f24b 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java @@ -46,7 +46,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.ui.R; import java.util.ArrayList; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java index 84e0ed3fc..e9ee2bde1 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java @@ -47,7 +47,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.ui.R; import java.util.ArrayList; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetDateDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetDateDialogFragment.java index 0fd6910ff..d81e51369 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetDateDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetDateDialogFragment.java @@ -12,7 +12,7 @@ import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentManager; -import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.view.widget.DateUtil; import java.util.Calendar; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java index 42b98af70..d3efca613 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java @@ -45,7 +45,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.ui.R; import java.util.ArrayList; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java index 1c7e3a12d..0d576066a 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java @@ -30,8 +30,8 @@ import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.graphql.field.HyperwalletField; +import com.hyperwallet.android.ui.R; import java.text.ParseException; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DefaultAccountWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DefaultAccountWidget.java index 99bfabc0b..f9a1401bf 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DefaultAccountWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DefaultAccountWidget.java @@ -13,7 +13,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.hyperwallet.android.hyperwallet_ui.R; +import com.hyperwallet.android.ui.R; public class DefaultAccountWidget extends AbstractWidget { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java index 8ae7dfacf..834629f85 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java @@ -38,8 +38,8 @@ import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.graphql.field.HyperwalletField; +import com.hyperwallet.android.ui.R; public class ExpiryDateWidget extends AbstractWidget { private final ExpireDateUtil mExpireDateUtil; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/NumberWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/NumberWidget.java index 2d4e9562c..dc20d4dc1 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/NumberWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/NumberWidget.java @@ -31,8 +31,8 @@ import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.graphql.field.HyperwalletField; +import com.hyperwallet.android.ui.R; public class NumberWidget extends AbstractWidget { private ViewGroup mContainer; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/PhoneWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/PhoneWidget.java index 346c1972c..8ce4aad9f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/PhoneWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/PhoneWidget.java @@ -31,8 +31,8 @@ import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.graphql.field.HyperwalletField; +import com.hyperwallet.android.ui.R; public class PhoneWidget extends AbstractWidget { private ViewGroup mContainer; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/SelectionWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/SelectionWidget.java index 102eea656..f6558922b 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/SelectionWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/SelectionWidget.java @@ -31,9 +31,9 @@ import androidx.core.content.ContextCompat; import com.google.android.material.textfield.TextInputLayout; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.graphql.field.HyperwalletField; import com.hyperwallet.android.model.graphql.field.HyperwalletFieldSelectionOption; +import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.view.WidgetSelectionDialogFragment; import java.util.Set; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/TextWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/TextWidget.java index 599b77b9a..9533752c5 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/TextWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/TextWidget.java @@ -31,8 +31,8 @@ import androidx.annotation.Nullable; import com.google.android.material.textfield.TextInputLayout; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.graphql.field.HyperwalletField; +import com.hyperwallet.android.ui.R; public class TextWidget extends AbstractWidget { private ViewGroup mContainer; diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml index 0c983668d..f77d5e91e 100644 --- a/ui/src/main/res/values/strings.xml +++ b/ui/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - hyperwallet_ui + hyperwallet.ui Add Account Not Available Unknown diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java index 269efa42e..ce5a9df3e 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java @@ -8,8 +8,8 @@ import android.content.Context; import android.content.res.Resources; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.graphql.HyperwalletFee; +import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; import org.json.JSONException; diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java index 6d57d30ff..186428ef3 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java @@ -14,8 +14,8 @@ import android.content.Context; import android.content.res.Resources; -import com.hyperwallet.android.hyperwallet_ui.R; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; import org.json.JSONException; From 4a71631f417af317a8a05dce5615298dbe1b7a2c Mon Sep 17 00:00:00 2001 From: Anna <48258136+azakrevska-epam@users.noreply.github.com> Date: Wed, 19 Jun 2019 00:56:03 +0300 Subject: [PATCH 017/177] HW-53765. renamed *Util to *Utils (#45) --- .../AddTransferMethodFragment.java | 4 +-- .../ui/view/WidgetDateDialogFragment.java | 8 +++--- .../widget/{DateUtil.java => DateUtils.java} | 4 +-- .../android/ui/view/widget/DateWidget.java | 8 +++--- ...pireDateUtil.java => ExpireDateUtils.java} | 4 +-- .../ui/view/widget/ExpiryDateWidget.java | 28 +++++++++---------- .../{DateUtilTest.java => DateUtilsTest.java} | 22 +++++++-------- ...UtilTest.java => ExpireDateUtilsTest.java} | 4 +-- 8 files changed, 41 insertions(+), 41 deletions(-) rename ui/src/main/java/com/hyperwallet/android/ui/view/widget/{DateUtil.java => DateUtils.java} (98%) rename ui/src/main/java/com/hyperwallet/android/ui/view/widget/{ExpireDateUtil.java => ExpireDateUtils.java} (99%) rename ui/src/test/java/com/hyperwallet/android/ui/view/widget/{DateUtilTest.java => DateUtilsTest.java} (73%) rename ui/src/test/java/com/hyperwallet/android/ui/view/widget/{ExpireDateUtilTest.java => ExpireDateUtilsTest.java} (97%) diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java index 471f184f5..e34075468 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java @@ -61,7 +61,7 @@ import com.hyperwallet.android.ui.view.WidgetSelectionDialogFragment; import com.hyperwallet.android.ui.view.widget.AbstractWidget; import com.hyperwallet.android.ui.view.widget.DateChangedListener; -import com.hyperwallet.android.ui.view.widget.DateUtil; +import com.hyperwallet.android.ui.view.widget.DateUtils; import com.hyperwallet.android.ui.view.widget.DateWidget; import com.hyperwallet.android.ui.view.widget.WidgetEventListener; import com.hyperwallet.android.ui.view.widget.WidgetFactory; @@ -99,7 +99,7 @@ public class AddTransferMethodFragment extends Fragment implements WidgetEventLi private HyperwalletTransferMethod mTransferMethod; private String mTransferMethodProfileType; private HashMap mWidgetInputStateHashMap; - private final DateUtil mDateUtil = new DateUtil(); + private final DateUtils mDateUtils = new DateUtils(); /** * Please do not use this to have instance of AddTransferMethodFragment this is reserved for android framework diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetDateDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetDateDialogFragment.java index d81e51369..274879b85 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetDateDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetDateDialogFragment.java @@ -13,7 +13,7 @@ import androidx.fragment.app.FragmentManager; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.view.widget.DateUtil; +import com.hyperwallet.android.ui.view.widget.DateUtils; import java.util.Calendar; @@ -23,7 +23,7 @@ public class WidgetDateDialogFragment extends DialogFragment { private static final String ARGUMENT_DATE = "ARGUMENT_DATE"; private static final String ARGUMENT_FIELD_NAME = "ARGUMENT_FIELD_NAME"; private OnSelectedDateCallback mOnSelectedDateCallback; - private final DateUtil mDateUtil = new DateUtil(); + private final DateUtils mDateUtils = new DateUtils(); /** * Please do not use this to have instance of DateDialogFragment this is reserved for android framework @@ -75,7 +75,7 @@ public Dialog onCreateDialog(@Nullable Bundle state) { final String fieldName = getArguments().getString(ARGUMENT_FIELD_NAME); Calendar calendar; try { - calendar = mDateUtil.convertDateFromServerFormatToCalendar(storedDate); + calendar = mDateUtils.convertDateFromServerFormatToCalendar(storedDate); } catch (Exception e) { calendar = Calendar.getInstance(); } @@ -85,7 +85,7 @@ public Dialog onCreateDialog(@Nullable Bundle state) { new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker view, int resultYear, int resultMonth, int resultDayOfMonth) { - final String selectedDate = mDateUtil + final String selectedDate = mDateUtils .buildDateFromDateDialogToServerFormat(resultYear, resultMonth, resultDayOfMonth); mOnSelectedDateCallback.setSelectedDateField(fieldName, selectedDate); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateUtil.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateUtils.java similarity index 98% rename from ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateUtil.java rename to ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateUtils.java index 8da501d0b..4c0ccb59f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateUtil.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateUtils.java @@ -31,7 +31,7 @@ /** * Class is used for manage and convert date {@link DateWidget} */ -public final class DateUtil { +public final class DateUtils { private static final String SERVER_DATE_PATTERN = "yyyy-MM-dd"; private static final String WIDGET_DATE_PATTERN = "dd MMMM yyyy"; @@ -39,7 +39,7 @@ public final class DateUtil { private final SimpleDateFormat mServerDateFormat = new SimpleDateFormat(SERVER_DATE_PATTERN, Locale.getDefault()); private final SimpleDateFormat mWidgetDateFormat; - public DateUtil() { + public DateUtils() { mWidgetDateFormat = new SimpleDateFormat( DateFormat.getBestDateTimePattern(Locale.getDefault(), WIDGET_DATE_PATTERN), Locale.getDefault()); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java index 0d576066a..c193db3d7 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/DateWidget.java @@ -37,7 +37,7 @@ public class DateWidget extends AbstractWidget implements DateChangedListener { - private final DateUtil mDateUtil; + private final DateUtils mDateUtils; private ViewGroup mContainer; private String mValue; private TextInputLayout mTextInputLayout; @@ -46,7 +46,7 @@ public class DateWidget extends AbstractWidget implements DateChangedListener { public DateWidget(@NonNull HyperwalletField field, @NonNull WidgetEventListener listener, @Nullable String defaultValue, @NonNull View defaultFocusView) { super(field, listener, defaultValue, defaultFocusView); - mDateUtil = new DateUtil(); + mDateUtils = new DateUtils(); mValue = defaultValue; } @@ -67,7 +67,7 @@ public View getView(@NonNull final ViewGroup viewGroup) { mEditText = new EditText( new ContextThemeWrapper(viewGroup.getContext(), R.style.Widget_Hyperwallet_TextInputEditText)); try { - mEditText.setText(mDateUtil.convertDateFromServerToWidgetFormat( + mEditText.setText(mDateUtils.convertDateFromServerToWidgetFormat( TextUtils.isEmpty(mDefaultValue) ? mValue = mField.getValue() : mDefaultValue)); } catch (ParseException e) { mEditText.setText(""); @@ -114,7 +114,7 @@ public void onUpdate(@Nullable final String selectedDate) { if (!TextUtils.isEmpty(selectedDate)) { mValue = selectedDate; try { - mEditText.setText(mDateUtil.convertDateFromServerToWidgetFormat(selectedDate)); + mEditText.setText(mDateUtils.convertDateFromServerToWidgetFormat(selectedDate)); mListener.saveTextChanged(getName(), getValue()); mListener.valueChanged(); } catch (ParseException e) { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtil.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtils.java similarity index 99% rename from ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtil.java rename to ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtils.java index aee64f92e..0e334ce8f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtil.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtils.java @@ -26,7 +26,7 @@ /** * Class is used for manage and convert card expire date {@link ExpiryDateWidget} */ -class ExpireDateUtil { +class ExpireDateUtils { static final char ONE_CHAR = '1'; static final int MAX_INPUT_LENGTH = 5; @@ -40,7 +40,7 @@ class ExpireDateUtil { private final Calendar mUpperValidDate = Calendar.getInstance(); - ExpireDateUtil() { + ExpireDateUtils() { mUpperValidDate.add(Calendar.YEAR, VALID_PERIOD_IN_YEARS); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java index 834629f85..9f2bde50f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/widget/ExpiryDateWidget.java @@ -16,10 +16,10 @@ */ package com.hyperwallet.android.ui.view.widget; -import static com.hyperwallet.android.ui.view.widget.ExpireDateUtil.MAX_INPUT_LENGTH; -import static com.hyperwallet.android.ui.view.widget.ExpireDateUtil.ONE_CHAR; -import static com.hyperwallet.android.ui.view.widget.ExpireDateUtil.SEPARATOR; -import static com.hyperwallet.android.ui.view.widget.ExpireDateUtil.ZERO_CHAR; +import static com.hyperwallet.android.ui.view.widget.ExpireDateUtils.MAX_INPUT_LENGTH; +import static com.hyperwallet.android.ui.view.widget.ExpireDateUtils.ONE_CHAR; +import static com.hyperwallet.android.ui.view.widget.ExpireDateUtils.SEPARATOR; +import static com.hyperwallet.android.ui.view.widget.ExpireDateUtils.ZERO_CHAR; import android.content.Context; import android.text.Editable; @@ -42,7 +42,7 @@ import com.hyperwallet.android.ui.R; public class ExpiryDateWidget extends AbstractWidget { - private final ExpireDateUtil mExpireDateUtil; + private final ExpireDateUtils mExpireDateUtils; private ViewGroup mContainer; private TextInputLayout mTextInputLayout; private String mValue; @@ -53,7 +53,7 @@ public ExpiryDateWidget(@NonNull HyperwalletField field, @NonNull WidgetEventLis @Nullable String defaultValue, @NonNull View defaultFocusView) { super(field, listener, defaultValue, defaultFocusView); mValue = defaultValue; - mExpireDateUtil = new ExpireDateUtil(); + mExpireDateUtils = new ExpireDateUtils(); } @Override @@ -82,7 +82,7 @@ public View getView(@NonNull final ViewGroup viewGroup) { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { - mValue = mExpireDateUtil.convertDateToServerFormat(((EditText) v).getText().toString()); + mValue = mExpireDateUtils.convertDateToServerFormat(((EditText) v).getText().toString()); mListener.valueChanged(); } else { mListener.widgetFocused(ExpiryDateWidget.this.getName()); @@ -141,9 +141,9 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { } } - dateParts = mExpireDateUtil.getDateParts(input); + dateParts = mExpireDateUtils.getDateParts(input); - if (!mExpireDateUtil.isValidMonth(dateParts[0])) { + if (!mExpireDateUtils.isValidMonth(dateParts[0])) { inErrorState = true; } @@ -161,7 +161,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { dateBuilder.append(dateParts[1]); String formattedDate = dateBuilder.toString(); - int cursorPosition = mExpireDateUtil.getCursorPosition(formattedDate.length(), changeStart, + int cursorPosition = mExpireDateUtils.getCursorPosition(formattedDate.length(), changeStart, insertionSize); ignoreConcurrentChanges = true; @@ -169,7 +169,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { editText.setSelection(cursorPosition); if (before != count) { - mValue = mExpireDateUtil.convertDateToServerFormat(formattedDate); + mValue = mExpireDateUtils.convertDateToServerFormat(formattedDate); mListener.saveTextChanged(getName(), mValue); } ignoreConcurrentChanges = false; @@ -182,7 +182,7 @@ public void afterTextChanged(Editable s) { editText.setInputType(InputType.TYPE_CLASS_DATETIME); editText.setHint(mField.getLabel()); - editText.setText(mExpireDateUtil.convertDateFromServerFormat( + editText.setText(mExpireDateUtils.convertDateFromServerFormat( TextUtils.isEmpty(mDefaultValue) ? mField.getValue() : mDefaultValue)); editText.setOnKeyListener(new DefaultKeyListener(mDefaultFocusView, editText)); @@ -219,7 +219,7 @@ public String getErrorMessage() { return mMessageInvalidDateLength; } - if (mExpireDateUtil.isInvalidDate(mValue)) { + if (mExpireDateUtils.isInvalidDate(mValue)) { return mMessageInvalidDate; } @@ -228,7 +228,7 @@ public String getErrorMessage() { @Override protected boolean isInvalidRegex() { - return mExpireDateUtil.isInvalidDate(mValue); + return mExpireDateUtils.isInvalidDate(mValue); } } diff --git a/ui/src/test/java/com/hyperwallet/android/ui/view/widget/DateUtilTest.java b/ui/src/test/java/com/hyperwallet/android/ui/view/widget/DateUtilsTest.java similarity index 73% rename from ui/src/test/java/com/hyperwallet/android/ui/view/widget/DateUtilTest.java rename to ui/src/test/java/com/hyperwallet/android/ui/view/widget/DateUtilsTest.java index d016de8af..7b96181d1 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/view/widget/DateUtilTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/view/widget/DateUtilsTest.java @@ -15,8 +15,8 @@ import java.util.Collection; @RunWith(RobolectricTestRunner.class) -public class DateUtilTest { - private final DateUtil mDateUtil = new DateUtil(); +public class DateUtilsTest { + private final DateUtils mDateUtils = new DateUtils(); @Rule public final ExpectedException mThrown = ExpectedException.none(); @@ -25,32 +25,32 @@ public class DateUtilTest { public void testConvertDateFromServerToWidgetFormat() throws Exception { String serverDate = "2005-05-23"; String widgetDate = "23 May 2005"; - assertThat(mDateUtil.convertDateFromServerToWidgetFormat(serverDate), is(widgetDate)); + assertThat(mDateUtils.convertDateFromServerToWidgetFormat(serverDate), is(widgetDate)); } @Test public void testBuildParamsDateFromServerToWidget_whenIncorrectDate() throws Exception { mThrown.expect(ParseException.class); - mDateUtil.convertDateFromServerToWidgetFormat("1990-01"); + mDateUtils.convertDateFromServerToWidgetFormat("1990-01"); } @Test public void testConvertDateFromServerToWidgetFormat_whenDateIsNullOrEmpty() throws Exception { - assertThat(mDateUtil.convertDateFromServerToWidgetFormat(""), is("")); - assertThat(mDateUtil.convertDateFromServerToWidgetFormat(null), is("")); + assertThat(mDateUtils.convertDateFromServerToWidgetFormat(""), is("")); + assertThat(mDateUtils.convertDateFromServerToWidgetFormat(null), is("")); } @Test public void testBuildParamsDateFromServerToCalendar_whenIncorrectDate() throws Exception { mThrown.expect(ParseException.class); - mDateUtil.convertDateFromServerFormatToCalendar("123-32").getTime(); + mDateUtils.convertDateFromServerFormatToCalendar("123-32").getTime(); } @Test public void testConvertDateFromServerFormatToCalendar_whenDateIsNullOrEmpty() throws ParseException { - assertThat(mDateUtil.convertDateFromServerFormatToCalendar(null).getTime().toString(), + assertThat(mDateUtils.convertDateFromServerFormatToCalendar(null).getTime().toString(), is(Calendar.getInstance().getTime().toString())); - assertThat(mDateUtil.convertDateFromServerFormatToCalendar("").getTime().toString(), + assertThat(mDateUtils.convertDateFromServerFormatToCalendar("").getTime().toString(), is(Calendar.getInstance().getTime().toString())); } @@ -59,7 +59,7 @@ public void testConvertDateFromServerFormatToCalendar() throws ParseException { String serverDate = "2005-05-23"; final Calendar mayCalendar = Calendar.getInstance(); mayCalendar.set(2005, 4, 23, 0, 0, 0); - assertThat(mDateUtil.convertDateFromServerFormatToCalendar(serverDate).getTime().toString(), + assertThat(mDateUtils.convertDateFromServerFormatToCalendar(serverDate).getTime().toString(), is(mayCalendar.getTime().toString())); } @@ -75,7 +75,7 @@ public void testBuildDateFromDateDialogToServerFormat() { month = (int) item[1]; dayOfMonth = (int) item[2]; widgetDate = (String) item[3]; - assertThat(mDateUtil.buildDateFromDateDialogToServerFormat(year, month, dayOfMonth), is(widgetDate)); + assertThat(mDateUtils.buildDateFromDateDialogToServerFormat(year, month, dayOfMonth), is(widgetDate)); } } diff --git a/ui/src/test/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtilTest.java b/ui/src/test/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtilsTest.java similarity index 97% rename from ui/src/test/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtilTest.java rename to ui/src/test/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtilsTest.java index d9f46e916..c0045f060 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtilTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/view/widget/ExpireDateUtilsTest.java @@ -15,8 +15,8 @@ import junitparams.Parameters; @RunWith(JUnitParamsRunner.class) -public class ExpireDateUtilTest { - private final ExpireDateUtil helper = new ExpireDateUtil(); +public class ExpireDateUtilsTest { + private final ExpireDateUtils helper = new ExpireDateUtils(); @Test @Parameters(method = "parametersToTestValidDate") From 87ee60b6e9d60bda0ea9b90021912c198ab4010a Mon Sep 17 00:00:00 2001 From: Peter Joseph Olamit Date: Wed, 19 Jun 2019 15:01:50 -0700 Subject: [PATCH 018/177] HW-52585 UI - Receipt Details (#42) --- .../ui/common/view}/OneClickListener.java | 5 +- .../android/ui/common/viewmodel/Event.java | 8 +- .../common/viewmodel/ListDetailNavigator.java | 30 ++ .../main/res/drawable/view_item_ripple.xml | 8 + common/src/main/res/values/styles.xml | 5 + receipt/build.gradle | 2 +- receipt/config/lint.xml | 3 + receipt/src/androidTest/AndroidManifest.xml | 3 +- ...yperwalletInstrumentedTestApplication.java | 31 ++ .../android/ui/receipt/ListReceiptsTest.java | 219 ++++++++- .../HyperwalletExternalResourceManager.java | 73 +++ .../rule/HyperwalletMockWebServer.java | 115 +++++ .../ui/receipt/util/EspressoUtils.java | 187 ++++++++ .../ui/receipt/util/NestedScrollToAction.java | 41 ++ .../util/RecyclerViewCountAssertion.java | 30 ++ .../util/TestAuthenticationProvider.java | 51 +++ receipt/src/main/AndroidManifest.xml | 12 +- .../receipt/repository/ReceiptDataSource.java | 11 +- .../ui/receipt/view/ListReceiptActivity.java | 21 +- .../ui/receipt/view/ListReceiptFragment.java | 108 +++-- .../receipt/view/ReceiptDetailActivity.java | 83 ++++ .../receipt/view/ReceiptDetailFragment.java | 220 +++++++++ .../viewmodel/ListReceiptViewModel.java | 9 + .../viewmodel/ReceiptDetailViewModel.java | 34 ++ .../res/layout/activity_receipt_detail.xml | 32 ++ ...fragment.xml => fragment_list_receipt.xml} | 0 .../res/layout/fragment_receipt_detail.xml | 425 ++++++++++++++++++ receipt/src/main/res/layout/item_receipt.xml | 70 +-- .../res/layout/item_receipt_with_header.xml | 10 +- receipt/src/main/res/layout/receipt.xml | 69 +++ receipt/src/main/res/values/strings.xml | 16 + .../repository/ReceiptDataSourceTest.java | 32 +- .../test/resources/receipt_list_response.json | 8 +- ui/src/androidTest/AndroidManifest.xml | 2 +- .../ListTransferMethodActivity.java | 2 +- .../ListTransferMethodFragment.java | 2 +- .../SelectTransferMethodFragment.java | 2 +- .../res/layout/item_transfer_method_type.xml | 3 +- 38 files changed, 1814 insertions(+), 168 deletions(-) rename {ui/src/main/java/com/hyperwallet/android/ui/view/widget => common/src/main/java/com/hyperwallet/android/ui/common/view}/OneClickListener.java (94%) create mode 100644 common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java create mode 100644 common/src/main/res/drawable/view_item_ripple.xml create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/HyperwalletInstrumentedTestApplication.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailActivity.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModel.java create mode 100644 receipt/src/main/res/layout/activity_receipt_detail.xml rename receipt/src/main/res/layout/{list_receipt_fragment.xml => fragment_list_receipt.xml} (100%) create mode 100644 receipt/src/main/res/layout/fragment_receipt_detail.xml create mode 100644 receipt/src/main/res/layout/receipt.xml diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/OneClickListener.java b/common/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java similarity index 94% rename from ui/src/main/java/com/hyperwallet/android/ui/view/widget/OneClickListener.java rename to common/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java index 33e575c31..e5822917b 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/widget/OneClickListener.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java @@ -1,6 +1,6 @@ /* * The MIT License (MIT) - * Copyright (c) 2018 Hyperwallet Systems Inc. + * Copyright (c) 2019 Hyperwallet Systems Inc. * * 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, @@ -14,7 +14,7 @@ * 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.view.widget; +package com.hyperwallet.android.ui.common.view; import android.os.SystemClock; import android.view.View; @@ -44,3 +44,4 @@ public void onClick(View v) { */ public abstract void onOneClick(View v); } + diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java b/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java index 0914c82f5..984bb9995 100644 --- a/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java +++ b/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java @@ -24,11 +24,11 @@ */ public class Event { - private final T content; + private final T mContent; private boolean mIsContentConsumed; public Event(@NonNull final T t) { - content = t; + mContent = t; } /** @@ -38,7 +38,7 @@ public Event(@NonNull final T t) { @NonNull public T getContent() { mIsContentConsumed = true; - return content; + return mContent; } /** @@ -58,7 +58,7 @@ public boolean isContentConsumed() { public T getContentIfNotConsumed() { if (!mIsContentConsumed) { mIsContentConsumed = true; - return content; + return mContent; } return null; } diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java b/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java new file mode 100644 index 000000000..b5916f1b2 --- /dev/null +++ b/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.common.viewmodel; + +/** + * Detail interface for having a list UI with detail information through navigation + */ +public interface ListDetailNavigator { + + /** + * Navigate action + * + * @param e Navigation event + */ + void navigate(Event e); +} diff --git a/common/src/main/res/drawable/view_item_ripple.xml b/common/src/main/res/drawable/view_item_ripple.xml new file mode 100644 index 000000000..4cabe0d43 --- /dev/null +++ b/common/src/main/res/drawable/view_item_ripple.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/common/src/main/res/values/styles.xml b/common/src/main/res/values/styles.xml index 8221087b3..ba0f0ee2d 100644 --- a/common/src/main/res/values/styles.xml +++ b/common/src/main/res/values/styles.xml @@ -232,6 +232,11 @@ @color/colorPrimaryDark @color/colorPrimary + + diff --git a/receipt/build.gradle b/receipt/build.gradle index 03133faa3..cff209c86 100644 --- a/receipt/build.gradle +++ b/receipt/build.gradle @@ -108,4 +108,4 @@ sonarqube { property "sonar.libraries", libraries property "sonar.projectName", "android-ui-sdk-receipt" } -} \ No newline at end of file +} diff --git a/receipt/config/lint.xml b/receipt/config/lint.xml index 3c83d4bb5..ff446fa9e 100644 --- a/receipt/config/lint.xml +++ b/receipt/config/lint.xml @@ -4,4 +4,7 @@ + + + \ No newline at end of file diff --git a/receipt/src/androidTest/AndroidManifest.xml b/receipt/src/androidTest/AndroidManifest.xml index eb1e37113..f65437a0d 100644 --- a/receipt/src/androidTest/AndroidManifest.xml +++ b/receipt/src/androidTest/AndroidManifest.xml @@ -2,7 +2,8 @@ - + diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/HyperwalletInstrumentedTestApplication.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/HyperwalletInstrumentedTestApplication.java new file mode 100644 index 000000000..fb0b7c4cc --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/HyperwalletInstrumentedTestApplication.java @@ -0,0 +1,31 @@ +package com.hyperwallet.android.ui.receipt; + + +import android.app.Application; + +import com.squareup.leakcanary.InstrumentationLeakDetector; +import com.squareup.leakcanary.LeakCanary; + +public class HyperwalletInstrumentedTestApplication extends Application { + + @Override + public void onCreate() { + + super.onCreate(); + if (LeakCanary.isInAnalyzerProcess(this)) { + // This process is dedicated to LeakCanary for heap analysis. + // You should not init your app in this process. + return; + } + installLeakCanary(); + } + + + protected void installLeakCanary() { + + InstrumentationLeakDetector.instrumentationRefWatcher(this) + .buildAndInstall(); + + } + +} \ No newline at end of file diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java index b68f3ec04..ee3bb4f03 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java @@ -1,9 +1,19 @@ package com.hyperwallet.android.ui.receipt; +import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_SHOW_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_TIME; +import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_SHOW_YEAR; +import static android.text.format.DateUtils.formatDateTime; + import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; 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; @@ -14,7 +24,7 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT; import static java.net.HttpURLConnection.HTTP_OK; -import static com.hyperwallet.android.util.EspressoUtils.atPosition; +import static com.hyperwallet.android.ui.receipt.util.EspressoUtils.atPosition; import android.content.Context; import android.content.res.Configuration; @@ -22,17 +32,21 @@ import android.widget.TextView; import androidx.test.core.app.ApplicationProvider; +import androidx.test.espresso.IdlingRegistry; import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.common.util.DateUtils; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.receipt.repository.ReceiptRepositoryFactory; +import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.receipt.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.receipt.util.RecyclerViewCountAssertion; +import com.hyperwallet.android.ui.receipt.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.receipt.view.ListReceiptActivity; -import com.hyperwallet.android.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.util.TestAuthenticationProvider; import org.junit.After; import org.junit.Before; @@ -41,7 +55,11 @@ import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Date; import java.util.Locale; +import java.util.concurrent.TimeUnit; + +import okhttp3.mockwebserver.MockResponse; @RunWith(AndroidJUnit4.class) public class ListReceiptsTest { @@ -69,8 +87,18 @@ public void cleanup() { ReceiptRepositoryFactory.clearInstance(); } + @Before + public void registerIdlingResource() { + IdlingRegistry.getInstance().register(EspressoIdlingResource.getIdlingResource()); + } + + @After + public void unregisterIdlingResource() { + IdlingRegistry.getInstance().unregister(EspressoIdlingResource.getIdlingResource()); + } + @Test - public void testListReceipts_userHasMultipleTransactions() { + public void testListReceipt_userHasMultipleTransactions() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("receipt_list_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); @@ -92,7 +120,7 @@ public void testListReceipts_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check( matches(atPosition(0, hasDescendant(withText("+ 20.00"))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(0, hasDescendant(withText("June 07, 2019"))))); + matches(atPosition(0, hasDescendant(withText("June 7, 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("USD"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(1, @@ -102,7 +130,7 @@ public void testListReceipts_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check( matches(atPosition(1, hasDescendant(withText("+ 25.00"))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(1, hasDescendant(withText("June 02, 2019"))))); + matches(atPosition(1, hasDescendant(withText("June 2, 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(1, hasDescendant(withText("CAD"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(2, @@ -112,7 +140,7 @@ public void testListReceipts_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check( matches(atPosition(2, hasDescendant(withText("- 1.95"))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(2, hasDescendant(withText("June 01, 2019"))))); + matches(atPosition(2, hasDescendant(withText("June 1, 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(2, hasDescendant(withText("USD"))))); onView(withId(R.id.list_receipts)) @@ -124,14 +152,14 @@ public void testListReceipts_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check( matches(atPosition(3, hasDescendant(withText("- 18.05"))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(3, hasDescendant(withText("December 01, 2018"))))); + matches(atPosition(3, hasDescendant(withText("December 1, 2018"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(3, hasDescendant(withText("USD"))))); onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(4)); } @Test - public void testListReceipts_displayCreditTransaction() { + public void testListReceipt_userHasCreditTransaction() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("receipt_credit_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); @@ -153,14 +181,14 @@ public void testListReceipts_displayCreditTransaction() { onView(withId(R.id.list_receipts)).check( matches(atPosition(0, hasDescendant(withText("+ 25.00"))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(0, hasDescendant(withText("June 02, 2019"))))); + matches(atPosition(0, hasDescendant(withText("June 2, 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("CAD"))))); onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); } @Test - public void testListReceipts_displayDebitTransaction() { + public void testListReceipt_userHasDebitTransaction() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("receipt_debit_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); @@ -182,14 +210,14 @@ public void testListReceipts_displayDebitTransaction() { onView(withId(R.id.list_receipts)).check( matches(atPosition(0, hasDescendant(withText("- 18.05"))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(0, hasDescendant(withText("May 02, 2019"))))); + matches(atPosition(0, hasDescendant(withText("May 2, 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("USD"))))); onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); } @Test - public void testListReceipts_displayUnknownTransactionType() { + public void testListReceipt_userHasUnknownTransactionType() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("receipt_unknown_type_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); @@ -211,7 +239,7 @@ public void testListReceipts_displayUnknownTransactionType() { onView(withId(R.id.list_receipts)).check( matches(atPosition(0, hasDescendant(withText("+ 25.00"))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(0, hasDescendant(withText("June 02, 2019"))))); + matches(atPosition(0, hasDescendant(withText("June 2, 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("CAD"))))); onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); @@ -231,7 +259,120 @@ public void testListReceipt_userHasNoTransactions() { } @Test - public void testListReceipt_displayPagedTransactions() throws InterruptedException { + public void testListReceipt_clickTransactionDisplaysDetails() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_list_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); + + onView(withId(R.id.transaction_header_text)).check(matches(withText(R.string.transaction_header_text))); + onView(withId(R.id.transaction_type_icon)).check(matches(withText(R.string.credit))); + onView(withId(R.id.transaction_title)).check(matches(withText(R.string.payment))); + onView(withId(R.id.transaction_amount)).check(matches(withText("+ 20.00"))); + onView(withId(R.id.transaction_currency)).check(matches(withText("USD"))); + onView(withId(R.id.transaction_date)).check(matches(withText("June 7, 2019"))); + + onView(withId(R.id.receipt_details_header_label)).check(matches(withText(R.string.receipt_header_label))); + onView(withId(R.id.receipt_id_label)).check(matches(withText(R.string.journalId))); + onView(withId(R.id.receipt_id_value)).check(matches(withText("3051579"))); + onView(withId(R.id.date_label)).check(matches(withText(R.string.createdOn))); + + Date date = DateUtils.fromDateTimeString("2019-06-07T17:08:58"); + String timezone = DateUtils.toDateFormat(date, "zzz"); + String text = mActivityTestRule.getActivity().getApplicationContext().getString( + R.string.concat_string_view_format, + formatDateTime(mActivityTestRule.getActivity().getApplicationContext(), date.getTime(), + FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_SHOW_YEAR + | FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_WEEKDAY), timezone); + onView(withId(R.id.date_value)).check(matches(withText(text))); + + onView(withId(R.id.client_id_label)).check(matches(withText(R.string.clientPaymentId))); + onView(withId(R.id.client_id_value)).check(matches(withText("8OxXefx5"))); + onView(withId(R.id.charity_label)).check(matches(withText(R.string.charityName))); + onView(withId(R.id.charity_value)).check(matches(withText("Sample Charity"))); + onView(withId(R.id.check_number_label)).check(matches(withText(R.string.checkNumber))); + onView(withId(R.id.check_number_value)).check(matches(withText("Sample Check Number"))); + onView(withId(R.id.website_label)).check(matches(withText(R.string.website))); + onView(withId(R.id.website_value)).check(matches(withText("https://api.sandbox.hyperwallet.com"))); + onView(withText("A Person")).check(doesNotExist()); + + onView(withId(R.id.receipt_notes_header_label)).check(matches(withText(R.string.notes))); + onView(withId(R.id.notes_value)).check( + matches(withText("Sample payment for the period of June 15th, 2019 to July 23, 2019"))); + + onView(withId(R.id.details_header_text)).check(matches(withText(R.string.fee_details_header_text))); + onView(withId(R.id.details_amount_label)).check(matches(withText(R.string.details_amount_label))); + onView(withId(R.id.details_amount_value)).check(matches(withText("20.00 USD"))); + onView(withId(R.id.details_fee_label)).check(matches(withText(R.string.fee_label))); + onView(withId(R.id.details_fee_value)).check(matches(withText("2.25 USD"))); + onView(withId(R.id.details_transfer_amount_label)).check(matches(withText(R.string.transfer_amount_label))); + onView(withId(R.id.details_transfer_amount_value)).check(matches(withText("17.75 USD"))); + } + + @Test + public void testListReceipt_clickTransactionDisplaysDetailsWithoutFees() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_list_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.actionOnItemAtPosition(3, click())); + + onView(withId(R.id.transaction_header_text)).check(matches(withText(R.string.transaction_header_text))); + onView(withId(R.id.transaction_type_icon)).check(matches(withText(R.string.debit))); + onView(withId(R.id.transaction_title)).check(matches(withText(R.string.transfer_to_prepaid_card))); + onView(withId(R.id.transaction_amount)).check(matches(withText("- 18.05"))); + onView(withId(R.id.transaction_currency)).check(matches(withText("USD"))); + onView(withId(R.id.transaction_date)).check(matches(withText("December 1, 2018"))); + + onView(withId(R.id.receipt_details_header_label)).check(matches(withText(R.string.receipt_header_label))); + onView(withId(R.id.receipt_id_label)).check(matches(withText(R.string.journalId))); + onView(withId(R.id.receipt_id_value)).check(matches(withText("3051590"))); + onView(withId(R.id.date_label)).check(matches(withText(R.string.createdOn))); + + Date date = DateUtils.fromDateTimeString("2018-12-01T17:12:18"); + String timezone = DateUtils.toDateFormat(date, "zzz"); + String text = mActivityTestRule.getActivity().getApplicationContext().getString( + R.string.concat_string_view_format, + formatDateTime(mActivityTestRule.getActivity().getApplicationContext(), date.getTime(), + FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_SHOW_YEAR + | FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_WEEKDAY), timezone); + onView(withId(R.id.date_value)).check(matches(withText(text))); + + onView(withId(R.id.client_id_label)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.client_id_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.charity_label)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.charity_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.check_number_label)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.check_number_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.website_label)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.website_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + + onView(withId(R.id.receipt_notes_information)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.receipt_notes_header_label)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.notes_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + } + + @Test + public void testListReceipt_verifyTransactionsLoadedUponScrolling() throws InterruptedException { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("receipt_list_paged_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager @@ -265,7 +406,7 @@ public void testListReceipt_displayPagedTransactions() throws InterruptedExcepti } @Test - public void testListReceipts_checkDateTextOnLocaleChange() { + public void testListReceipt_checkDateTextOnLocaleChange() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("receipt_debit_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); @@ -276,13 +417,47 @@ public void testListReceipts_checkDateTextOnLocaleChange() { // assert onView(withId(R.id.list_receipts)) .check(matches(atPosition(0, hasDescendant(withText("maggio 2019"))))); - onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("maggio 02, 2019"))))); - mActivityTestRule.finishActivity(); - setLocale(Locale.US); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("2 maggio 2019"))))); + } + + @Test + public void testListReceipt_displaysNetworkErrorDialogOnConnectionTimeout() { + mMockWebServer.getServer().enqueue(new MockResponse().setResponseCode(HTTP_OK).setBody(sResourceManager + .getResourceContent("receipt_debit_response.json")).throttleBody(512, 15, TimeUnit.SECONDS)); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("receipt_debit_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + mActivityTestRule.launchActivity(null); + + // assert error dialog information exist in portrait mode + onView(withText(R.string.error_dialog_connectivity_title)).check(matches(isDisplayed())); + onView(withText(R.string.io_exception)).check(matches(isDisplayed())); + onView(withId(android.R.id.button1)).check(matches(withText(R.string.try_again_button_label))); + onView(withId(android.R.id.button2)).check(matches(withText(R.string.cancel_button_label))); + + // retry button clicked + onView(withId(android.R.id.button1)).perform(click()); + onView(withText(R.string.error_dialog_connectivity_title)).check(doesNotExist()); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + onView(withId(R.id.list_receipts)) .check(matches(atPosition(0, hasDescendant(withText("May 2019"))))); - onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("May 02, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.transfer_to_prepaid_card))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("- 18.05"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("May 2, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); } private void setLocale(Locale locale) { diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java new file mode 100644 index 000000000..b5baa31da --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java @@ -0,0 +1,73 @@ +package com.hyperwallet.android.ui.receipt.rule; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class HyperwalletExternalResourceManager extends TestWatcher { + + private static final String EMPTY = ""; + private ClassLoader classLoader; + private Logger logger; + + @Override + protected void starting(Description description) { + super.starting(description); + classLoader = description.getTestClass().getClassLoader(); + logger = Logger.getLogger(description.getTestClass().getName()); + } + + public String getResourceContent(final String resourceName) { + if (resourceName == null) { + throw new IllegalArgumentException("Parameter resourceName cannot be null"); + } + + return getContent(resourceName); + } + + private String getContent(final String resourceName) { + + URL resource = classLoader.getResource(resourceName); + InputStream inputStream = null; + Writer writer = new StringWriter(); + String resourceContent = EMPTY; + if (resource != null) { + try { + inputStream = resource.openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + String line = reader.readLine(); + while (line != null) { + writer.write(line); + line = reader.readLine(); + } + resourceContent = writer.toString(); + + } catch (Exception e) { + logger.log(Level.WARNING, "There was an error loading an external resource", e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "There was an error closing input stream", e); + } + try { + writer.close(); + } catch (IOException e) { + logger.log(Level.SEVERE, "There was an error closing writer", e); + } + } + } + return resourceContent; + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java new file mode 100644 index 000000000..fd55bd2bb --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java @@ -0,0 +1,115 @@ +package com.hyperwallet.android.ui.receipt.rule; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +import java.io.IOException; +import java.net.HttpURLConnection; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +public final class HyperwalletMockWebServer extends TestWatcher { + + private MockWebServer mServer; + private int port; + + public HyperwalletMockWebServer(int port) { + this.port = port; + } + + @Override + protected void starting(Description description) { + super.starting(description); + mServer = new MockWebServer(); + try { + mServer.start(port); + } catch (IOException e) { + throw new IllegalStateException("Unable to start mock server", e); + } + } + + @Override + protected void finished(Description description) { + super.finished(description); + try { + mServer.shutdown(); + mServer.close(); + } catch (IOException e) { + throw new IllegalStateException("Un error occurred when shutting down mock server", e); + } + } + + public HyperwalletMockResponse mockResponse() { + return new Builder(mServer).build(); + } + + public MockWebServer getServer() { + return mServer; + } + + public static class HyperwalletMockResponse { + + private String path; + private String body; + private int httpResponseCode; + private Builder builder; + + HyperwalletMockResponse(Builder builder) { + this.path = builder.path; + this.httpResponseCode = builder.responseCode; + this.body = builder.body; + this.builder = builder; + } + + public HyperwalletMockResponse withHttpResponseCode(final int code) { + builder.responseCode(code); + return builder.build(); + } + + public HyperwalletMockResponse withBody(final String body) { + builder.body(body); + return builder.build(); + } + + public void mock() { + mockRequest(); + } + + private String mockRequest() { + builder.server.enqueue(new MockResponse().setResponseCode(httpResponseCode).setBody(body)); + return builder.server.url(path).toString(); + } + + } + + private static class Builder { + + private String path; + private String body; + private int responseCode; + private MockWebServer server; + + + Builder(final MockWebServer server) { + this.path = ""; + this.responseCode = HttpURLConnection.HTTP_OK; + this.body = ""; + this.server = server; + } + + Builder responseCode(final int code) { + this.responseCode = code; + return this; + } + + Builder body(final String body) { + this.body = body; + return this; + } + + HyperwalletMockResponse build() { + return new HyperwalletMockResponse(this); + } + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java new file mode 100644 index 000000000..549a99704 --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java @@ -0,0 +1,187 @@ +package com.hyperwallet.android.ui.receipt.util; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.EditText; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.action.ViewActions; +import androidx.test.espresso.matcher.BoundedMatcher; + +import com.google.android.material.textfield.TextInputLayout; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import java.util.Objects; + +public class EspressoUtils { + + public static Matcher withHint(final String expectedHint) { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof TextInputLayout)) { + return false; + } + + String hint = Objects.toString(((TextInputLayout) view).getHint()); + return expectedHint.equals(hint); + } + + @Override + public void describeTo(Description description) { + description.appendText(expectedHint); + } + }; + } + + public static Matcher hasErrorText(final String expectedErrorMessage) { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof TextInputLayout)) { + return false; + } + + String errorMessage = Objects.toString(((TextInputLayout) view).getError()); + return expectedErrorMessage.equals(errorMessage); + } + + @Override + public void describeTo(Description description) { + description.appendText(expectedErrorMessage); + } + }; + } + + public static Matcher hasErrorText(final int resourceId) { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof TextInputLayout)) { + return false; + } + String expectedErrorMessage = view.getResources().getString(resourceId); + String errorMessage = Objects.toString(((TextInputLayout) view).getError()); + + return expectedErrorMessage.equals(errorMessage); + } + + @Override + public void describeTo(Description description) { + } + }; + } + + public static Matcher withDrawable(final int resourceId) { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof ImageView)) { + return false; + } + + Drawable drawable = ((ImageView) view).getDrawable(); + if (drawable == null) { + return false; + } + Drawable expectedDrawable = view.getContext().getResources().getDrawable(resourceId); + + Bitmap bitmap = getBitmap(drawable); + Bitmap expectedBitmap = getBitmap(expectedDrawable); + + return bitmap.sameAs(expectedBitmap); + } + + @Override + public void describeTo(Description description) { + } + }; + } + + public static Matcher atPosition(final int position, @NonNull final Matcher matcher) { + return new BoundedMatcher(RecyclerView.class) { + + @Override + protected boolean matchesSafely(final RecyclerView view) { + RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(position); + + if (viewHolder == null) { + return false; + } + + return matcher.matches(viewHolder.itemView); + } + + @Override + public void describeTo(Description description) { + description.appendText("has item at position " + position + ": "); + matcher.describeTo(description); + } + }; + } + + public static ViewAction nestedScrollTo() { + return ViewActions.actionWithAssertions(new NestedScrollToAction()); + } + + private static Bitmap getBitmap(Drawable drawable) { + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + + return bitmap; + } + + public static Matcher hasNoErrorText() { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof TextInputLayout)) { + return false; + } + return ((TextInputLayout) view).getError() == null; + } + + @Override + public void describeTo(Description description) { + description.appendText("has no error text: "); + } + }; + } + + public static Matcher hasEmptyText() { + return new TypeSafeMatcher() { + + @Override + public boolean matchesSafely(View view) { + if (!(view instanceof EditText)) { + return false; + } + String text = ((EditText) view).getText().toString(); + + return text.isEmpty(); + } + + @Override + public void describeTo(Description description) { + } + }; + } +} + diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java new file mode 100644 index 000000000..b3619e5c3 --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java @@ -0,0 +1,41 @@ +package com.hyperwallet.android.ui.receipt.util; + +import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; +import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; + +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.anyOf; + +import android.view.View; + +import androidx.core.widget.NestedScrollView; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.action.ScrollToAction; +import androidx.test.espresso.matcher.ViewMatchers; + +import org.hamcrest.Matcher; + +public class NestedScrollToAction implements ViewAction { + private static final String TAG = ScrollToAction.class.getSimpleName(); + + @SuppressWarnings("unchecked") + @Override + public Matcher getConstraints() { + return allOf( + withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), + isDescendantOfA( + anyOf(isAssignableFrom(NestedScrollView.class)))); + } + + @Override + public void perform(UiController uiController, View view) { + new ScrollToAction().perform(uiController, view); + } + + @Override + public String getDescription() { + return "scroll to"; + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java new file mode 100644 index 000000000..7420f7e5c --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java @@ -0,0 +1,30 @@ +package com.hyperwallet.android.ui.receipt.util; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.espresso.ViewAssertion; + +public class RecyclerViewCountAssertion implements ViewAssertion { + private final int mCount; + + public RecyclerViewCountAssertion(int count) { + this.mCount = count; + } + + @Override + public void check(View view, NoMatchingViewException noViewFoundException) { + if (noViewFoundException != null) { + throw noViewFoundException; + } + + RecyclerView recyclerView = (RecyclerView) view; + RecyclerView.Adapter adapter = recyclerView.getAdapter(); + + assertThat(adapter.getItemCount(), is(mCount)); + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java new file mode 100644 index 000000000..c50513b47 --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java @@ -0,0 +1,51 @@ +package com.hyperwallet.android.ui.receipt.util; + +import com.hyperwallet.android.HyperwalletAuthenticationTokenListener; +import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.UUID; + +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +public class TestAuthenticationProvider implements HyperwalletAuthenticationTokenProvider { + + public static final MediaType JSON + = MediaType.get("application/json; charset=utf-8"); + private static final String mBaseUrl = "http://localhost:8080/rest/v3/users/{0}/authentication-token"; + private static final String mUserToken = "user_token"; + + @Override + public void retrieveAuthenticationToken(final HyperwalletAuthenticationTokenListener authenticationTokenListener) { + + OkHttpClient client = new OkHttpClient(); + + String payload = "{}"; + String baseUrl = MessageFormat.format(mBaseUrl, mUserToken); + + RequestBody body = RequestBody.create(JSON, payload); + Request request = new Request.Builder() + .url(baseUrl) + .post(body) + .build(); + + client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + authenticationTokenListener.onFailure(UUID.randomUUID(), e.getMessage()); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + authenticationTokenListener.onSuccess(response.body().string()); + } + }); + } +} diff --git a/receipt/src/main/AndroidManifest.xml b/receipt/src/main/AndroidManifest.xml index d817501e5..fbfa141a9 100644 --- a/receipt/src/main/AndroidManifest.xml +++ b/receipt/src/main/AndroidManifest.xml @@ -5,10 +5,16 @@ - - + + + \ No newline at end of file diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java index f6e30479b..fd0c3b654 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java @@ -31,6 +31,7 @@ import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.model.receipt.ReceiptQueryParam; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.common.viewmodel.Event; import java.util.Calendar; @@ -71,7 +72,8 @@ public void loadInitial(@NonNull final LoadInitialParams params, .limit(params.requestedLoadSize) .sortByCreatedOnDesc().build(); - getHyperwallet().listReceipts(queryParam, + EspressoIdlingResource.increment(); + getHyperwallet().listUserReceipts(queryParam, new HyperwalletListener>() { @Override public void onSuccess(@Nullable HyperwalletPageList result) { @@ -86,12 +88,14 @@ public void onSuccess(@Nullable HyperwalletPageList result) { // reset mLoadInitialCallback = null; mLoadInitialParams = null; + EspressoIdlingResource.decrement(); } @Override public void onFailure(HyperwalletException exception) { mIsFetchingData.postValue(Boolean.FALSE); mErrors.postValue(new Event<>(exception.getHyperwalletErrors())); + EspressoIdlingResource.decrement(); } @Override @@ -129,7 +133,8 @@ public void loadAfter(@NonNull LoadParams params, .offset(params.key) .sortByCreatedOnDesc().build(); - getHyperwallet().listReceipts(queryParam, + EspressoIdlingResource.increment(); + getHyperwallet().listUserReceipts(queryParam, new HyperwalletListener>() { @Override public void onSuccess(@Nullable HyperwalletPageList result) { @@ -144,12 +149,14 @@ public void onSuccess(@Nullable HyperwalletPageList result) { // reset mLoadAfterCallback = null; mLoadAfterParams = null; + EspressoIdlingResource.decrement(); } @Override public void onFailure(HyperwalletException exception) { mIsFetchingData.postValue(Boolean.FALSE); mErrors.postValue(new Event<>(exception.getHyperwalletErrors())); + EspressoIdlingResource.decrement(); } @Override diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java index 6f203949d..ef56fa89b 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java @@ -32,16 +32,19 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.viewmodel.ListDetailNavigator; import com.hyperwallet.android.ui.receipt.R; import com.hyperwallet.android.ui.receipt.repository.ReceiptRepositoryFactory; import com.hyperwallet.android.ui.receipt.viewmodel.ListReceiptViewModel; import java.util.List; -public class ListReceiptActivity extends AppCompatActivity implements OnNetworkErrorCallback { +public class ListReceiptActivity extends AppCompatActivity implements OnNetworkErrorCallback, + ListDetailNavigator> { private ListReceiptViewModel mListReceiptViewModel; @@ -76,6 +79,13 @@ public void onChanged(Event event) { } }); + mListReceiptViewModel.getDetailNavigation().observe(this, new Observer>() { + @Override + public void onChanged(Event event) { + navigate(event); + } + }); + if (savedInstanceState == null) { initFragment(ListReceiptFragment.newInstance()); } @@ -130,4 +140,13 @@ private void showErrorOnLoadReceipt(@NonNull final List errors fragment.show(fragmentManager); } } + + @Override + public void navigate(@NonNull final Event event) { + if (!event.isContentConsumed()) { + Intent intent = new Intent(this, ReceiptDetailActivity.class); + intent.putExtra(ReceiptDetailActivity.EXTRA_RECEIPT, event.getContent()); + startActivity(intent); + } + } } diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java index 2e2e33cac..e1fd220a2 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java @@ -16,6 +16,11 @@ */ package com.hyperwallet.android.ui.receipt.view; +import static android.text.format.DateUtils.FORMAT_NO_MONTH_DAY; +import static android.text.format.DateUtils.FORMAT_SHOW_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_YEAR; +import static android.text.format.DateUtils.formatDateTime; + import static com.hyperwallet.android.model.receipt.Receipt.Entries.CREDIT; import static com.hyperwallet.android.model.receipt.Receipt.Entries.DEBIT; @@ -39,10 +44,13 @@ import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.ui.common.util.DateUtils; +import com.hyperwallet.android.ui.common.view.OneClickListener; import com.hyperwallet.android.ui.receipt.R; import com.hyperwallet.android.ui.receipt.viewmodel.ListReceiptViewModel; +import java.text.DecimalFormat; import java.util.Calendar; +import java.util.Date; import java.util.Locale; import java.util.Objects; @@ -77,14 +85,14 @@ public void onCreate(@Nullable final Bundle savedInstanceState) { @Override public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.list_receipt_fragment, container, false); + return inflater.inflate(R.layout.fragment_list_receipt, container, false); } @Override public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mProgressBar = view.findViewById(R.id.list_receipt_progress_bar); - mListReceiptAdapter = new ListReceiptAdapter(new ListReceiptItemDiffCallback()); + mListReceiptAdapter = new ListReceiptAdapter(mListReceiptViewModel, new ListReceiptItemDiffCallback()); mListReceiptsView = view.findViewById(R.id.list_receipts); mListReceiptsView.setHasFixedSize(true); mListReceiptsView.setLayoutManager(new LinearLayoutManager(getActivity())); @@ -96,8 +104,8 @@ public void onViewCreated(@NonNull final View view, @Nullable final Bundle saved private void registerObservers() { mListReceiptViewModel.getReceiptList().observe(getViewLifecycleOwner(), new Observer>() { @Override - public void onChanged(PagedList transferMethods) { - mListReceiptAdapter.submitList(transferMethods); + public void onChanged(PagedList receipts) { + mListReceiptAdapter.submitList(receipts); } }); @@ -135,13 +143,15 @@ public boolean areContentsTheSame(@NonNull final Receipt oldItem, @NonNull final private static class ListReceiptAdapter extends PagedListAdapter { - private static final String HEADER_DATE_FORMAT = "MMMM yyyy"; - private static final String CAPTION_DATE_FORMAT = "MMMM dd, yyyy"; + static final String AMOUNT_FORMAT = "###0.00"; private static final int HEADER_VIEW_TYPE = 1; private static final int DATA_VIEW_TYPE = 0; + private final ListReceiptViewModel mReceiptViewModel; - ListReceiptAdapter(@NonNull final DiffUtil.ItemCallback diffCallback) { + ListReceiptAdapter(@NonNull final ListReceiptViewModel receiptViewModel, + @NonNull final DiffUtil.ItemCallback diffCallback) { super(diffCallback); + mReceiptViewModel = receiptViewModel; } @Override @@ -173,10 +183,10 @@ public ReceiptViewHolder onCreateViewHolder(final @NonNull ViewGroup viewGroup, if (viewType == HEADER_VIEW_TYPE) { View headerView = layout.inflate(R.layout.item_receipt_with_header, viewGroup, false); - return new ReceiptViewHolderWithHeader(headerView); + return new ReceiptViewHolderWithHeader(mReceiptViewModel, headerView); } View dataView = layout.inflate(R.layout.item_receipt, viewGroup, false); - return new ReceiptViewHolder(dataView); + return new ReceiptViewHolder(mReceiptViewModel, dataView); } @Override @@ -188,48 +198,64 @@ public void onBindViewHolder(@NonNull final ReceiptViewHolder holder, final int } class ReceiptViewHolder extends RecyclerView.ViewHolder { - private final TextView mTransactionAmount; - private final TextView mTransactionCurrency; - private final TextView mTransactionDate; - private final TextView mTransactionTitle; - private final TextView mTransactionTypeIcon; - ReceiptViewHolder(@NonNull final View item) { + private ListReceiptViewModel mListReceiptViewModel; + private View mView; + + ReceiptViewHolder(@NonNull final ListReceiptViewModel receiptViewModel, + @NonNull final View item) { super(item); - mTransactionAmount = item.findViewById(R.id.transaction_amount); - mTransactionCurrency = item.findViewById(R.id.transaction_currency); - mTransactionDate = item.findViewById(R.id.transaction_date); - mTransactionTitle = item.findViewById(R.id.transaction_title); - mTransactionTypeIcon = item.findViewById(R.id.transaction_type_icon); + mView = item.findViewById(R.id.receipt_item); + mListReceiptViewModel = receiptViewModel; } void bind(@NonNull final Receipt receipt) { + mView.setOnClickListener(new OneClickListener() { + @Override + public void onOneClick(View v) { + mListReceiptViewModel.setDetailNavigation(receipt); + } + }); + + // By design decision from here under, this code is also repeated in ReceiptDetailFragment + TextView transactionTypeIcon = itemView.findViewById(R.id.transaction_type_icon); + TextView transactionTitle = itemView.findViewById(R.id.transaction_title); + TextView transactionDate = itemView.findViewById(R.id.transaction_date); + TextView transactionAmount = itemView.findViewById(R.id.transaction_amount); + TextView transactionCurrency = itemView.findViewById(R.id.transaction_currency); + + //TODO localization of currencies in consideration + DecimalFormat decimalFormat = new DecimalFormat(AMOUNT_FORMAT); + double amount = Double.parseDouble(receipt.getAmount()); + String formattedAmount = decimalFormat.format(amount); + if (CREDIT.equals(receipt.getEntry())) { - mTransactionAmount.setTextColor(mTransactionAmount.getContext() + transactionAmount.setTextColor(transactionAmount.getContext() .getResources().getColor(R.color.positiveColor)); - mTransactionAmount.setText(mTransactionAmount.getContext() - .getString(R.string.credit_sign, receipt.getAmount())); - mTransactionTypeIcon.setTextColor(mTransactionTypeIcon.getContext() + transactionAmount.setText(transactionAmount.getContext() + .getString(R.string.credit_sign, formattedAmount)); + transactionTypeIcon.setTextColor(transactionTypeIcon.getContext() .getResources().getColor(R.color.positiveColor)); - mTransactionTypeIcon.setBackground(mTransactionTypeIcon.getContext() + transactionTypeIcon.setBackground(transactionTypeIcon.getContext() .getDrawable(R.drawable.circle_positive)); - mTransactionTypeIcon.setText(mTransactionTypeIcon.getContext().getText(R.string.credit)); + transactionTypeIcon.setText(transactionTypeIcon.getContext().getText(R.string.credit)); } else if (DEBIT.equals(receipt.getEntry())) { - mTransactionAmount.setTextColor(mTransactionAmount.getContext() + transactionAmount.setTextColor(transactionAmount.getContext() .getResources().getColor(R.color.colorAccent)); - mTransactionAmount.setText(mTransactionAmount.getContext() - .getString(R.string.debit_sign, receipt.getAmount())); - mTransactionTypeIcon.setTextColor(mTransactionTypeIcon.getContext() + transactionAmount.setText(transactionAmount.getContext() + .getString(R.string.debit_sign, formattedAmount)); + transactionTypeIcon.setTextColor(transactionTypeIcon.getContext() .getResources().getColor(R.color.colorAccent)); - mTransactionTypeIcon.setBackground(mTransactionTypeIcon.getContext() + transactionTypeIcon.setBackground(transactionTypeIcon.getContext() .getDrawable(R.drawable.circle_negative)); - mTransactionTypeIcon.setText(mTransactionTypeIcon.getContext().getText(R.string.debit)); + transactionTypeIcon.setText(transactionTypeIcon.getContext().getText(R.string.debit)); } - mTransactionCurrency.setText(receipt.getCurrency()); - mTransactionTitle.setText(getTransactionTitle(receipt.getType(), mTransactionTitle.getContext())); - mTransactionDate.setText(DateUtils.toDateFormat(DateUtils. - fromDateTimeString(receipt.getCreatedOn()), CAPTION_DATE_FORMAT)); + transactionCurrency.setText(receipt.getCurrency()); + transactionTitle.setText(getTransactionTitle(receipt.getType(), transactionTitle.getContext())); + Date date = DateUtils.fromDateTimeString(receipt.getCreatedOn()); + transactionDate.setText(formatDateTime(itemView.getContext(), date.getTime(), + FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR)); } String getTransactionTitle(@NonNull final String receiptType, @NonNull final Context context) { @@ -248,16 +274,18 @@ class ReceiptViewHolderWithHeader extends ReceiptViewHolder { private final TextView mTransactionHeaderText; - ReceiptViewHolderWithHeader(@NonNull final View item) { - super(item); + ReceiptViewHolderWithHeader(@NonNull final ListReceiptViewModel receiptViewModel, + @NonNull final View item) { + super(receiptViewModel, item); mTransactionHeaderText = item.findViewById(R.id.item_date_header_title); } @Override void bind(@NonNull final Receipt receipt) { super.bind(receipt); - mTransactionHeaderText.setText(DateUtils.toDateFormat( - DateUtils.fromDateTimeString(receipt.getCreatedOn()), HEADER_DATE_FORMAT)); + Date date = DateUtils.fromDateTimeString(receipt.getCreatedOn()); + mTransactionHeaderText.setText(formatDateTime(mTransactionHeaderText.getContext(), date.getTime(), + FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NO_MONTH_DAY)); } } } diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailActivity.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailActivity.java new file mode 100644 index 000000000..9dd1a85fa --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailActivity.java @@ -0,0 +1,83 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.view; + +import android.os.Bundle; +import android.os.Parcelable; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.ViewModelProviders; + +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.receipt.R; +import com.hyperwallet.android.ui.receipt.viewmodel.ReceiptDetailViewModel; + +public class ReceiptDetailActivity extends AppCompatActivity { + + public static final String EXTRA_RECEIPT = "RECEIPT"; + + @Override + protected void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_receipt_detail); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + getSupportActionBar().setTitle(R.string.title_activity_receipt_detail); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + Parcelable parcel = getIntent().getParcelableExtra(EXTRA_RECEIPT); + if (parcel instanceof Receipt) { + ReceiptDetailViewModel viewModel = ViewModelProviders.of(this).get(ReceiptDetailViewModel.class); + viewModel.setReceipt((Receipt) parcel); + } else { + throw new IllegalArgumentException("Argument is not an instance of " + + ReceiptDetailActivity.class.getName()); + } + + if (savedInstanceState == null) { + initFragment(ReceiptDetailFragment.newInstance()); + } + } + + private void initFragment(@NonNull final Fragment fragment) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.add(R.id.receipt_detail_fragment, fragment); + fragmentTransaction.commit(); + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java new file mode 100644 index 000000000..8e8f99dec --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java @@ -0,0 +1,220 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.view; + +import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_SHOW_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_TIME; +import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_SHOW_YEAR; +import static android.text.format.DateUtils.formatDateTime; + +import static com.hyperwallet.android.model.receipt.Receipt.Entries.CREDIT; +import static com.hyperwallet.android.model.receipt.Receipt.Entries.DEBIT; + +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProviders; + +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.model.receipt.ReceiptDetails; +import com.hyperwallet.android.ui.common.util.DateUtils; +import com.hyperwallet.android.ui.receipt.R; +import com.hyperwallet.android.ui.receipt.viewmodel.ReceiptDetailViewModel; + +import java.text.DecimalFormat; +import java.util.Date; +import java.util.Locale; + +public class ReceiptDetailFragment extends Fragment { + + static final String AMOUNT_FORMAT = "###0.00"; + static final String DETAIL_TIMEZONE = "zzz"; + + private ReceiptDetailViewModel mReceiptDetailViewModel; + + public ReceiptDetailFragment() { + } + + public static ReceiptDetailFragment newInstance() { + ReceiptDetailFragment fragment = new ReceiptDetailFragment(); + return fragment; + } + + @Override + public void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mReceiptDetailViewModel = ViewModelProviders.of(requireActivity()).get(ReceiptDetailViewModel.class); + } + + @Override + public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, + @Nullable final Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_receipt_detail, container, false); + } + + @Override + public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + Receipt receipt = mReceiptDetailViewModel.getReceipt(); + + // transactions + setTransactionView(receipt, view); + + // receipt details + setDetailsView(receipt, view); + + // fee details + setFeeDetailsView(receipt, view); + } + + // By design decision, this code is also repeated in ListReceiptFragment + private void setTransactionView(@NonNull final Receipt receipt, @NonNull final View view) { + TextView transactionTypeIcon = view.findViewById(R.id.transaction_type_icon); + TextView transactionTitle = view.findViewById(R.id.transaction_title); + TextView transactionDate = view.findViewById(R.id.transaction_date); + TextView transactionAmount = view.findViewById(R.id.transaction_amount); + TextView transactionCurrency = view.findViewById(R.id.transaction_currency); + + //TODO localization of currencies in consideration + DecimalFormat decimalFormat = new DecimalFormat(AMOUNT_FORMAT); + double amount = Double.parseDouble(receipt.getAmount()); + String formattedAmount = decimalFormat.format(amount); + + if (CREDIT.equals(receipt.getEntry())) { + transactionAmount.setTextColor(transactionAmount.getContext() + .getResources().getColor(R.color.positiveColor)); + transactionAmount.setText(transactionAmount.getContext() + .getString(R.string.credit_sign, formattedAmount)); + transactionTypeIcon.setTextColor(transactionTypeIcon.getContext() + .getResources().getColor(R.color.positiveColor)); + transactionTypeIcon.setBackground(transactionTypeIcon.getContext() + .getDrawable(R.drawable.circle_positive)); + transactionTypeIcon.setText(transactionTypeIcon.getContext().getText(R.string.credit)); + } else if (DEBIT.equals(receipt.getEntry())) { + transactionAmount.setTextColor(transactionAmount.getContext() + .getResources().getColor(R.color.colorAccent)); + transactionAmount.setText(transactionAmount.getContext() + .getString(R.string.debit_sign, formattedAmount)); + transactionTypeIcon.setTextColor(transactionTypeIcon.getContext() + .getResources().getColor(R.color.colorAccent)); + transactionTypeIcon.setBackground(transactionTypeIcon.getContext() + .getDrawable(R.drawable.circle_negative)); + transactionTypeIcon.setText(transactionTypeIcon.getContext().getText(R.string.debit)); + } + + transactionCurrency.setText(receipt.getCurrency()); + transactionTitle.setText(getTransactionTitle(receipt.getType(), transactionTitle.getContext())); + Date date = DateUtils.fromDateTimeString(receipt.getCreatedOn()); + transactionDate.setText(formatDateTime(view.getContext(), date.getTime(), + FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR)); + } + + private String getTransactionTitle(@NonNull final String receiptType, @NonNull final Context context) { + String showTitle = context.getResources().getString(R.string.unknown_type); + int resourceId = context.getResources().getIdentifier(receiptType.toLowerCase(Locale.ROOT), "string", + context.getPackageName()); + if (resourceId != 0) { + showTitle = context.getResources().getString(resourceId); + } + + return showTitle; + } + + private void setFeeDetailsView(@NonNull final Receipt receipt, @NonNull final View view) { + if (!TextUtils.isEmpty(receipt.getFee())) { + view.findViewById(R.id.fee_details_layout).setVisibility(View.VISIBLE); + double feeAmount = Double.parseDouble(receipt.getFee()); + double amount = Double.parseDouble(receipt.getAmount()); + double transferAmount = amount - feeAmount; + + //TODO localization of currencies in consideration + DecimalFormat decimalFormat = new DecimalFormat(AMOUNT_FORMAT); + + TextView amountView = view.findViewById(R.id.details_amount_value); + amountView.setText(view.getContext().getString(R.string.concat_string_view_format, + decimalFormat.format(amount), receipt.getCurrency())); + + TextView fee = view.findViewById(R.id.details_fee_value); + fee.setText(view.getContext().getString(R.string.concat_string_view_format, + decimalFormat.format(feeAmount), receipt.getCurrency())); + + TextView transfer = view.findViewById(R.id.details_transfer_amount_value); + transfer.setText(view.getContext().getString(R.string.concat_string_view_format, + decimalFormat.format(transferAmount), receipt.getCurrency())); + } + } + + private void setDetailsView(@NonNull final Receipt receipt, @NonNull final View view) { + TextView receiptId = view.findViewById(R.id.receipt_id_value); + receiptId.setText(receipt.getJournalId()); + TextView dateView = view.findViewById(R.id.date_value); + + Date date = DateUtils.fromDateTimeString(receipt.getCreatedOn()); + String timezone = DateUtils.toDateFormat(date, DETAIL_TIMEZONE); + dateView.setText(view.getContext().getString(R.string.concat_string_view_format, + formatDateTime(view.getContext(), date.getTime(), + FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_SHOW_YEAR + | FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_WEEKDAY), timezone)); + + if (receipt.getDetails() != null) { + ReceiptDetails receiptDetails = receipt.getDetails(); + if (!TextUtils.isEmpty(receiptDetails.getCharityName())) { + setViewInformation(R.id.charity_layout, R.id.charity_value, + view, receiptDetails.getCharityName()); + } + + if (!TextUtils.isEmpty(receiptDetails.getCheckNumber())) { + setViewInformation(R.id.check_number_layout, R.id.check_number_value, + view, receiptDetails.getCheckNumber()); + } + + if (!TextUtils.isEmpty(receiptDetails.getClientPaymentId())) { + setViewInformation(R.id.client_id_layout, R.id.client_id_value, + view, receiptDetails.getClientPaymentId()); + } + + if (!TextUtils.isEmpty(receiptDetails.getWebsite())) { + setViewInformation(R.id.website_layout, R.id.website_value, + view, receiptDetails.getWebsite()); + } + + if (!TextUtils.isEmpty(receiptDetails.getNotes())) { + setViewInformation(R.id.receipt_notes_information, R.id.notes_value, + view, receiptDetails.getNotes()); + } + } + } + + private void setViewInformation(@IdRes final int layout, @IdRes final int viewValue, + @NonNull final View view, @NonNull final String value) { + view.findViewById(layout).setVisibility(View.VISIBLE); + TextView textView = view.findViewById(viewValue); + textView.setText(value); + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java index 264e78974..0d1533a58 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java @@ -32,6 +32,7 @@ public class ListReceiptViewModel extends ViewModel { private MutableLiveData> mErrorEvent = new MutableLiveData<>(); + private MutableLiveData> mDetailNavigation = new MutableLiveData<>(); private Observer> mErrorEventObserver; private ReceiptRepository mReceiptRepository; @@ -66,6 +67,14 @@ public void retryLoadReceipts() { mReceiptRepository.retryLoadReceipt(); } + public LiveData> getDetailNavigation() { + return mDetailNavigation; + } + + public void setDetailNavigation(@NonNull final Receipt receipt) { + mDetailNavigation.postValue(new Event<>(receipt)); + } + @Override protected void onCleared() { super.onCleared(); diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModel.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModel.java new file mode 100644 index 000000000..8d628168d --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModel.java @@ -0,0 +1,34 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.viewmodel; + +import androidx.lifecycle.ViewModel; + +import com.hyperwallet.android.model.receipt.Receipt; + +public class ReceiptDetailViewModel extends ViewModel { + + private Receipt mReceipt; + + public Receipt getReceipt() { + return mReceipt; + } + + public void setReceipt(Receipt receipt) { + mReceipt = receipt; + } +} diff --git a/receipt/src/main/res/layout/activity_receipt_detail.xml b/receipt/src/main/res/layout/activity_receipt_detail.xml new file mode 100644 index 000000000..d2b7c038a --- /dev/null +++ b/receipt/src/main/res/layout/activity_receipt_detail.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + diff --git a/receipt/src/main/res/layout/list_receipt_fragment.xml b/receipt/src/main/res/layout/fragment_list_receipt.xml similarity index 100% rename from receipt/src/main/res/layout/list_receipt_fragment.xml rename to receipt/src/main/res/layout/fragment_list_receipt.xml diff --git a/receipt/src/main/res/layout/fragment_receipt_detail.xml b/receipt/src/main/res/layout/fragment_receipt_detail.xml new file mode 100644 index 000000000..a9abb5ea6 --- /dev/null +++ b/receipt/src/main/res/layout/fragment_receipt_detail.xml @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/layout/item_receipt.xml b/receipt/src/main/res/layout/item_receipt.xml index 83a0fe875..cfb204c4c 100644 --- a/receipt/src/main/res/layout/item_receipt.xml +++ b/receipt/src/main/res/layout/item_receipt.xml @@ -1,74 +1,10 @@ - - - - - - - - - - + \ No newline at end of file diff --git a/receipt/src/main/res/layout/item_receipt_with_header.xml b/receipt/src/main/res/layout/item_receipt_with_header.xml index 29f002169..9256f3ff8 100644 --- a/receipt/src/main/res/layout/item_receipt_with_header.xml +++ b/receipt/src/main/res/layout/item_receipt_with_header.xml @@ -21,6 +21,14 @@ android:textAppearance="@style/TextAppearance.Hyperwallet.Body2"/> - + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/layout/receipt.xml b/receipt/src/main/res/layout/receipt.xml new file mode 100644 index 000000000..88429d094 --- /dev/null +++ b/receipt/src/main/res/layout/receipt.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/values/strings.xml b/receipt/src/main/res/values/strings.xml index 6c6730a9e..b40bd2485 100644 --- a/receipt/src/main/res/values/strings.xml +++ b/receipt/src/main/res/values/strings.xml @@ -1,6 +1,22 @@ receipt Transactions + Transaction Details + Transaction + Fee Specification + Amount: + Fee: + Transfer Amount: + Receipt + Receipt ID: + Date: + Client Transaction ID: + Notes + Charity Name: + Check Number: + Promo Website: + %s %s + Seems like, you don\'t have any Transactions, yet. diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java index 9cf699e83..50aa0ad5e 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java @@ -96,13 +96,13 @@ public Object answer(InvocationOnMock invocation) { listener.onSuccess(response); return listener; } - }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + }).when(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); // test mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); - verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mInitialCallback).onResult(mListArgumentCaptor.capture(), mPreviousCaptor.capture(), mNextCaptor.capture()); @@ -149,13 +149,13 @@ public Object answer(InvocationOnMock invocation) { listener.onSuccess(null); return listener; } - }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + }).when(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); // test mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); - verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt(), anyInt()); @@ -177,13 +177,13 @@ public Object answer(InvocationOnMock invocation) { listener.onFailure(new HyperwalletException(errors)); return listener; } - }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + }).when(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); // test mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); - verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt(), anyInt()); @@ -211,13 +211,13 @@ public Object answer(InvocationOnMock invocation) { listener.onFailure(new HyperwalletException(errors)); return listener; } - }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + }).when(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); // test mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); - verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt(), anyInt()); @@ -248,13 +248,13 @@ public Object answer(InvocationOnMock invocation) { listener.onSuccess(response); return listener; } - }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + }).when(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); // test mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); - verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mLoadAfterCallback).onResult(mListArgumentCaptor.capture(), mNextCaptor.capture()); @@ -299,13 +299,13 @@ public Object answer(InvocationOnMock invocation) { listener.onSuccess(null); return listener; } - }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + }).when(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); // test mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); - verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.>any(), anyInt()); @@ -327,13 +327,13 @@ public Object answer(InvocationOnMock invocation) { listener.onFailure(new HyperwalletException(errors)); return listener; } - }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + }).when(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); // test mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); - verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt()); @@ -362,13 +362,13 @@ public Object answer(InvocationOnMock invocation) { listener.onFailure(new HyperwalletException(errors)); return listener; } - }).when(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + }).when(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); // test mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); - verify(mHyperwallet).listReceipts(any(ReceiptQueryParam.class), + verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt()); diff --git a/receipt/src/test/resources/receipt_list_response.json b/receipt/src/test/resources/receipt_list_response.json index 7e7cc58af..4ec2de4fe 100644 --- a/receipt/src/test/resources/receipt_list_response.json +++ b/receipt/src/test/resources/receipt_list_response.json @@ -11,11 +11,15 @@ "sourceToken": "act-12345", "destinationToken": "usr-fa76a738-f43d-48b9-9a7a-7048d44a5d2d", "amount": "20.00", - "fee": "0.00", + "fee": "2.25", "currency": "USD", "details": { "clientPaymentId": "8OxXefx5", - "payeeName": "A Person" + "payeeName": "A Person", + "website": "https://api.sandbox.hyperwallet.com", + "notes": "Sample payment for the period of June 15th, 2019 to July 23, 2019", + "charityName": "Sample Charity", + "checkNumber": "Sample Check Number" } }, { diff --git a/ui/src/androidTest/AndroidManifest.xml b/ui/src/androidTest/AndroidManifest.xml index ac7de9735..138dc247d 100644 --- a/ui/src/androidTest/AndroidManifest.xml +++ b/ui/src/androidTest/AndroidManifest.xml @@ -2,7 +2,7 @@ - + diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java index 64ba48309..6aef7e314 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java @@ -33,9 +33,9 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.view.OneClickListener; import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; -import com.hyperwallet.android.ui.view.widget.OneClickListener; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java index 634bc0af2..34b93cf50 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java @@ -54,8 +54,8 @@ import com.hyperwallet.android.ui.HyperwalletLocalBroadcast; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.common.view.HorizontalDividerItemDecorator; +import com.hyperwallet.android.ui.common.view.OneClickListener; import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.view.widget.OneClickListener; import java.util.ArrayList; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java index 8c757bb2e..5f284a8d4 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java @@ -41,10 +41,10 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.common.view.HorizontalDividerItemDecorator; +import com.hyperwallet.android.ui.common.view.OneClickListener; import com.hyperwallet.android.ui.repository.RepositoryFactory; import com.hyperwallet.android.ui.view.CountrySelectionDialogFragment; import com.hyperwallet.android.ui.view.CurrencySelectionDialogFragment; -import com.hyperwallet.android.ui.view.widget.OneClickListener; import java.util.ArrayList; import java.util.List; diff --git a/ui/src/main/res/layout/item_transfer_method_type.xml b/ui/src/main/res/layout/item_transfer_method_type.xml index 2e6045e68..973409968 100644 --- a/ui/src/main/res/layout/item_transfer_method_type.xml +++ b/ui/src/main/res/layout/item_transfer_method_type.xml @@ -29,8 +29,7 @@ android:layout_marginStart="@dimen/grid_margin_left" android:layout_marginTop="@dimen/grid_margin_top" android:text="@string/not_available" - android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1" - android:textStyle="bold" + android:textAppearance="@style/TextAppearance.Hyperwallet.Subtitle1" app:layout_constraintLeft_toRightOf="@+id/transfer_method_type_icon" app:layout_constraintTop_toTopOf="parent" /> From 18fccd738ed61df24d908abefef243d0a1568ff6 Mon Sep 17 00:00:00 2001 From: vshcherbyna-epam <48257687+vshcherbyna-epam@users.noreply.github.com> Date: Sat, 22 Jun 2019 00:39:04 +0300 Subject: [PATCH 019/177] HW-52637 pay pal account second line (#44) --- .../ListTransferMethodTest.java | 5 +- .../ListTransferMethodFragment.java | 42 ++++---------- .../transfermethod/TransferMethodUtils.java | 55 +++++++++++++++++++ .../TransferMethodUtilsTest.java | 49 +++++++++++++++++ 4 files changed, 120 insertions(+), 31 deletions(-) diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java index 3f8412743..fc567b50e 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java @@ -131,6 +131,8 @@ public void testListTransferMethod_userHasMultipleTransferMethods() { onView(withId(R.id.list_transfer_method_item)).check( matches(atPosition(3, hasDescendant(withText(R.string.paper_check))))); onView(withId(R.id.list_transfer_method_item)).check(matches(atPosition(3, hasDescendant(withText("Canada"))))); + onView(withId(R.id.list_transfer_method_item)).check( + matches(atPosition(3, hasDescendant(withText(""))))); onView(withId(R.id.list_transfer_method_item)).check( matches(atPosition(3, hasDescendant(withDrawable(R.drawable.ic_three_dots_16dp))))); @@ -150,7 +152,8 @@ public void testListTransferMethod_userHasMultipleTransferMethods() { matches(atPosition(5, hasDescendant(withText(R.string.paypal_account))))); onView(withId(R.id.list_transfer_method_item)).check( matches(atPosition(5, hasDescendant(withText("United States"))))); - //TODO: Try to check for non existence of transfer_method_type_description_2 + onView(withId(R.id.list_transfer_method_item)).check( + matches(atPosition(5, hasDescendant(withText("honey.thigpen@ukbuilder.com"))))); onView(withId(R.id.list_transfer_method_item)).check( matches(atPosition(5, hasDescendant(withDrawable(R.drawable.ic_three_dots_16dp))))); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java index 34b93cf50..e38385540 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java @@ -16,16 +16,11 @@ */ package com.hyperwallet.android.ui.transfermethod; -import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.BANK_ACCOUNT_ID; -import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.CARD_NUMBER; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TYPE; -import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; -import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; -import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.PREPAID_CARD; -import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.WIRE_ACCOUNT; import static com.hyperwallet.android.ui.transfermethod.TransferMethodUtils.getStringFontIcon; import static com.hyperwallet.android.ui.transfermethod.TransferMethodUtils.getStringResourceByName; +import static com.hyperwallet.android.ui.transfermethod.TransferMethodUtils.getTransferMethodDetail; import android.content.Context; import android.content.Intent; @@ -65,7 +60,7 @@ public class ListTransferMethodFragment extends Fragment implements ListTransfer static final String ARGUMENT_IS_TRANSFER_METHODS_RELOAD_NEEDED = "ARGUMENT_IS_TRANSFER_METHODS_RELOAD_NEEDED"; - private static final int LAST_FOUR_DIGIT = 4; + private static final String ARGUMENT_TRANSFER_METHOD_LIST = "ARGUMENT_TRANSFER_METHOD_LIST"; private View mEmptyListView; @@ -310,7 +305,7 @@ private static class ListTransferMethodAdapter extends RecyclerView.Adapter LAST_FOUR_DIGIT - ? transferIdentification.substring(transferIdentification.length() - LAST_FOUR_DIGIT) - : transferIdentification); - } @Override public int getItemCount() { @@ -373,16 +351,20 @@ class ViewHolder extends RecyclerView.ViewHolder { void bind(@NonNull final HyperwalletTransferMethod transferMethod) { + String type = transferMethod.getField(TYPE); + final String transferMethodIdentification = getTransferMethodDetail( + mTransferMethodIdentification.getContext(), + transferMethod, + type); + mTitle.setText( - getStringResourceByName(mTitle.getContext(), transferMethod.getField(TYPE))); + getStringResourceByName(mTitle.getContext(), type)); Locale locale = new Locale.Builder().setRegion( transferMethod.getField(TRANSFER_METHOD_COUNTRY)).build(); - mIcon.setText(getStringFontIcon(mIcon.getContext(), transferMethod.getField(TYPE))); + mIcon.setText(getStringFontIcon(mIcon.getContext(), type)); mTransferMethodCountry.setText(locale.getDisplayName()); - mTransferMethodIdentification.setText(mTransferMethodIdentification - .getContext().getString(R.string.transfer_method_list_item_description, - getAccountIdentifier(transferMethod))); + mTransferMethodIdentification.setText(transferMethodIdentification); mImageButton.setOnClickListener(new View.OnClickListener() { @Override diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java index 127c21818..2566e479f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.java @@ -16,6 +16,9 @@ */ package com.hyperwallet.android.ui.transfermethod; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.BANK_ACCOUNT_ID; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.CARD_NUMBER; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.EMAIL; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TYPE; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; @@ -28,6 +31,8 @@ import android.content.res.Resources; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodType; @@ -37,6 +42,8 @@ public class TransferMethodUtils { + private static final int LAST_FOUR_DIGIT = 4; + /** * Get string resource by TransferMethodType * @@ -125,4 +132,52 @@ public static String getTransferMethodName(@NonNull final Context context, return title; } + + /** + * Gets Transfer method identifier from the {@link HyperwalletTransferMethod} field + * by a {@link TransferMethodType}. + * + * @param context Context + * @param transferMethod HyperwalletTransferMethod + * @param type TransferMethodType + */ + public static String getTransferMethodDetail(@NonNull Context context, + @NonNull final HyperwalletTransferMethod transferMethod, + @Nullable @TransferMethodType final String type) { + if (type == null) { + return ""; + } + + switch (type) { + case BANK_CARD: + case PREPAID_CARD: + return getFourDigitsIdentification(context, + transferMethod, + CARD_NUMBER, + R.string.transfer_method_list_item_description); + case BANK_ACCOUNT: + case WIRE_ACCOUNT: + return getFourDigitsIdentification(context, transferMethod, BANK_ACCOUNT_ID, + R.string.transfer_method_list_item_description); + case PAYPAL_ACCOUNT: + final String transferIdentification = transferMethod.getField(EMAIL); + return transferIdentification != null ? transferIdentification : ""; + default: + return ""; + } + } + + private static String getFourDigitsIdentification(@NonNull final Context context, + @NonNull final HyperwalletTransferMethod transferMethod, + @NonNull @HyperwalletTransferMethod.TransferMethodFieldKey final String fieldKey, + @StringRes final int stringResId) { + final String transferIdentification = transferMethod.getField(fieldKey); + + final String identificationText = + transferIdentification != null && transferIdentification.length() > LAST_FOUR_DIGIT + ? transferIdentification.substring(transferIdentification.length() - LAST_FOUR_DIGIT) + : ""; + + return context.getString(stringResId, identificationText); + } } diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java index 186428ef3..7fd0bbece 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java @@ -5,19 +5,28 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.PAPER_CHECK; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT; +import static com.hyperwallet.android.ui.transfermethod.TransferMethodUtils.getTransferMethodDetail; import android.content.Context; import android.content.res.Resources; +import com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount; +import com.hyperwallet.android.model.transfermethod.HyperwalletBankCard; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.model.transfermethod.PayPalAccount; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; +import org.hamcrest.CoreMatchers; import org.json.JSONException; import org.json.JSONObject; import org.junit.Before; @@ -134,4 +143,44 @@ public void testGetStringFontIcon_returnsDefaultValue() { verify(mResources, times(2)).getIdentifier(anyString(), anyString(), anyString()); verify(mContext, times(1)).getString(anyInt()); } + + @Test + public void getTransferMethodDetail_returnsPayPalDetails() { + HyperwalletTransferMethod transferMethod = new PayPalAccount.Builder().email( + "sunshine.carreiro@hyperwallet.com").build(); + + String actual = getTransferMethodDetail(mContext, transferMethod, PAYPAL_ACCOUNT); + assertThat(actual, is("sunshine.carreiro@hyperwallet.com")); + } + + @Test + public void getTransferMethodDetail_returnsCardDetails() { + HyperwalletTransferMethod transferMethod = new HyperwalletBankCard.Builder().cardNumber( + "************0006").build(); + + when(mContext.getString(eq(R.string.transfer_method_list_item_description), eq("0006"))).thenReturn( + "Ending on 0006"); + String actual = getTransferMethodDetail(mContext, transferMethod, BANK_CARD); + assertThat(actual, is("Ending on 0006")); + } + + @Test + public void getTransferMethodDetail_returnsBankAccountDetails() { + HyperwalletTransferMethod transferMethod = new HyperwalletBankAccount.Builder().bankAccountId( + "8017110254").build(); + + when(mContext.getString(eq(R.string.transfer_method_list_item_description), eq("0254"))).thenReturn( + "Ending on 0254"); + String actual = getTransferMethodDetail(mContext, transferMethod, BANK_ACCOUNT); + assertThat(actual, is("Ending on 0254")); + } + + @Test + public void getTransferMethodDetail_returnsPaperCheckDetails() { + HyperwalletTransferMethod transferMethod = new HyperwalletTransferMethod(); + + String actual = getTransferMethodDetail(mContext, transferMethod, PAPER_CHECK); + assertThat(actual, CoreMatchers.is("")); + verify(mContext, never()).getString(eq(R.string.transfer_method_list_item_description), anyString()); + } } From b06d464fa2af52f0d22e1b64d785f42ec9d0a275 Mon Sep 17 00:00:00 2001 From: Peter Joseph Olamit Date: Tue, 2 Jul 2019 14:01:59 -0700 Subject: [PATCH 020/177] HW-53039 receipt view ppc (#49) --- .../receipt/ListPrepaidCardReceiptsTest.java | 107 +++++ ...ptsTest.java => ListUserReceiptsTest.java} | 16 +- receipt/src/main/AndroidManifest.xml | 17 +- .../PrepaidCardReceiptDataSource.java | 198 +++++++++ .../PrepaidCardReceiptDataSourceFactory.java | 54 +++ .../PrepaidCardReceiptRepository.java | 55 +++ .../PrepaidCardReceiptRepositoryImpl.java | 75 ++++ .../repository/ReceiptRepositoryFactory.java | 56 --- ...Source.java => UserReceiptDataSource.java} | 20 +- ...java => UserReceiptDataSourceFactory.java} | 22 +- ...sitory.java => UserReceiptRepository.java} | 8 +- ...pl.java => UserReceiptRepositoryImpl.java} | 24 +- .../view/ListPrepaidCardReceiptActivity.java | 143 +++++++ .../ui/receipt/view/ListReceiptFragment.java | 35 +- ...vity.java => ListUserReceiptActivity.java} | 28 +- .../receipt/view/ReceiptDetailFragment.java | 4 +- .../ListPrepaidCardReceiptViewModel.java | 130 ++++++ ...del.java => ListUserReceiptViewModel.java} | 58 ++- .../receipt/viewmodel/ReceiptViewModel.java | 59 +++ .../activity_list_prepaid_card_receipt.xml | 41 ++ ...ipt.xml => activity_list_user_receipt.xml} | 6 +- .../main/res/layout/fragment_list_receipt.xml | 25 ++ ...epaidCardReceiptDataSourceFactoryTest.java | 38 ++ .../PrepaidCardReceiptDataSourceTest.java | 396 ++++++++++++++++++ .../ReceiptRepositoryFactoryTest.java | 39 -- ... => UserReceiptDataSourceFactoryTest.java} | 10 +- ...st.java => UserReceiptDataSourceTest.java} | 74 ++-- .../resources/prepaid_card_receipt_list.json | 96 +++++ .../ListTransferMethodTest.java | 2 +- .../hyperwallet/android/ui/HyperwalletUi.java | 22 +- 30 files changed, 1602 insertions(+), 256 deletions(-) create mode 100644 receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java rename receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/{ListReceiptsTest.java => ListUserReceiptsTest.java} (98%) create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactory.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java delete mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactory.java rename receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/{ReceiptDataSource.java => UserReceiptDataSource.java} (91%) rename receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/{ReceiptDataSourceFactory.java => UserReceiptDataSourceFactory.java} (67%) rename receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/{ReceiptRepository.java => UserReceiptRepository.java} (89%) rename receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/{ReceiptRepositoryImpl.java => UserReceiptRepositoryImpl.java} (79%) create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java rename receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/{ListReceiptActivity.java => ListUserReceiptActivity.java} (83%) create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java rename receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/{ListReceiptViewModel.java => ListUserReceiptViewModel.java} (62%) create mode 100644 receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java create mode 100644 receipt/src/main/res/layout/activity_list_prepaid_card_receipt.xml rename receipt/src/main/res/layout/{activity_list_receipt.xml => activity_list_user_receipt.xml} (91%) create mode 100644 receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactoryTest.java create mode 100644 receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java delete mode 100644 receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactoryTest.java rename receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/{ReceiptDataSourceFactoryTest.java => UserReceiptDataSourceFactoryTest.java} (72%) rename receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/{ReceiptDataSourceTest.java => UserReceiptDataSourceTest.java} (85%) create mode 100644 receipt/src/test/resources/prepaid_card_receipt_list.json diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java new file mode 100644 index 000000000..e9076ea1e --- /dev/null +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java @@ -0,0 +1,107 @@ +package com.hyperwallet.android.ui.receipt; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +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 org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.instanceOf; + +import static java.net.HttpURLConnection.HTTP_NO_CONTENT; +import static java.net.HttpURLConnection.HTTP_OK; + +import static com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity.EXTRA_PREPAID_CARD_TOKEN; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.widget.TextView; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.espresso.IdlingRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.rule.ActivityTestRule; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; +import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.receipt.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.receipt.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity; + +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.util.Locale; + +@RunWith(AndroidJUnit4.class) +public class ListPrepaidCardReceiptsTest { + + @ClassRule + public static HyperwalletExternalResourceManager sResourceManager = new HyperwalletExternalResourceManager(); + @Rule + public HyperwalletMockWebServer mMockWebServer = new HyperwalletMockWebServer(8080); + @Rule + public ActivityTestRule mActivityTestRule = + new ActivityTestRule(ListPrepaidCardReceiptActivity.class, true, false) { + @Override + protected Intent getActivityIntent() { + Intent intent = new Intent(ApplicationProvider.getApplicationContext(), + ListPrepaidCardReceiptActivity.class); + intent.putExtra(EXTRA_PREPAID_CARD_TOKEN, "trm-test-token"); + return intent; + } + }; + + @Before + public void setup() { + Hyperwallet.getInstance(new TestAuthenticationProvider()); + + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("authentication_token_response.json")).mock(); + + setLocale(Locale.US); + IdlingRegistry.getInstance().register(EspressoIdlingResource.getIdlingResource()); + } + + @After + public void unregisterIdlingResource() { + IdlingRegistry.getInstance().unregister(EspressoIdlingResource.getIdlingResource()); + } + + @Test + public void testListReceipt_userHasMultipleTransactions() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("prepaid_card_receipt_list.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + } + + private void setLocale(Locale locale) { + Context context = ApplicationProvider.getApplicationContext(); + Locale.setDefault(locale); + Resources resources = context.getResources(); + Configuration configuration = resources.getConfiguration(); + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.JELLY_BEAN) { + configuration.setLocale(locale); + } else { + configuration.locale = locale; + } + resources.updateConfiguration(configuration, resources.getDisplayMetrics()); + } +} diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java similarity index 98% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java rename to receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java index ee3bb4f03..f510302c4 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListReceiptsTest.java +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java @@ -41,12 +41,11 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.ui.common.util.DateUtils; import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; -import com.hyperwallet.android.ui.receipt.repository.ReceiptRepositoryFactory; import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.receipt.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.receipt.util.RecyclerViewCountAssertion; import com.hyperwallet.android.ui.receipt.util.TestAuthenticationProvider; -import com.hyperwallet.android.ui.receipt.view.ListReceiptActivity; +import com.hyperwallet.android.ui.receipt.view.ListUserReceiptActivity; import org.junit.After; import org.junit.Before; @@ -62,15 +61,15 @@ import okhttp3.mockwebserver.MockResponse; @RunWith(AndroidJUnit4.class) -public class ListReceiptsTest { +public class ListUserReceiptsTest { @ClassRule public static HyperwalletExternalResourceManager sResourceManager = new HyperwalletExternalResourceManager(); @Rule public HyperwalletMockWebServer mMockWebServer = new HyperwalletMockWebServer(8080); @Rule - public ActivityTestRule mActivityTestRule = - new ActivityTestRule<>(ListReceiptActivity.class, true, false); + public ActivityTestRule mActivityTestRule = + new ActivityTestRule<>(ListUserReceiptActivity.class, true, false); @Before public void setup() { @@ -82,11 +81,6 @@ public void setup() { setLocale(Locale.US); } - @After - public void cleanup() { - ReceiptRepositoryFactory.clearInstance(); - } - @Before public void registerIdlingResource() { IdlingRegistry.getInstance().register(EspressoIdlingResource.getIdlingResource()); @@ -372,7 +366,7 @@ public void testListReceipt_clickTransactionDisplaysDetailsWithoutFees() { } @Test - public void testListReceipt_verifyTransactionsLoadedUponScrolling() throws InterruptedException { + public void testListReceipt_verifyTransactionsLoadedUponScrolling() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("receipt_list_paged_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager diff --git a/receipt/src/main/AndroidManifest.xml b/receipt/src/main/AndroidManifest.xml index fbfa141a9..2c573851d 100644 --- a/receipt/src/main/AndroidManifest.xml +++ b/receipt/src/main/AndroidManifest.xml @@ -6,13 +6,18 @@ - - + android:networkSecurityConfig="@xml/network_security_config" + tools:targetApi="n"> + + diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java new file mode 100644 index 000000000..352ae0913 --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java @@ -0,0 +1,198 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.repository; + +import android.os.Handler; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.paging.PageKeyedDataSource; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.listener.HyperwalletListener; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.paging.HyperwalletPageList; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.model.receipt.ReceiptQueryParam; +import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.util.DateUtil; + +import java.util.Calendar; +import java.util.Date; + +/** + * PrepaidCardReceiptDataSource mediates communication to HW API Platform particularly on + * Receipts PrepaidCard V3 API + */ +public class PrepaidCardReceiptDataSource extends PageKeyedDataSource { + + private static final int YEAR_BEFORE_NOW = -1; + + private final Calendar mCalendarYearBeforeNow; + private final String mToken; + private final MutableLiveData> mErrors = new MutableLiveData<>(); + private final MutableLiveData mIsFetchingData = new MutableLiveData<>(); + private PageKeyedDataSource.LoadCallback mLoadAfterCallback; + private PageKeyedDataSource.LoadParams mLoadAfterParams; + private PageKeyedDataSource.LoadInitialCallback mLoadInitialCallback; + private PageKeyedDataSource.LoadInitialParams mLoadInitialParams; + + /** + * Initialize Prepaid card data source + * + * @param token Prepaid card token identifier, please get this data from HW Platform + */ + PrepaidCardReceiptDataSource(@NonNull final String token) { + mToken = token; + mCalendarYearBeforeNow = Calendar.getInstance(); + mCalendarYearBeforeNow.add(Calendar.YEAR, YEAR_BEFORE_NOW); + } + + /** + * @see PageKeyedDataSource#loadInitial(LoadInitialParams, LoadInitialCallback) + */ + @Override + public void loadInitial(@NonNull final LoadInitialParams params, + @NonNull final LoadInitialCallback callback) { + mLoadInitialCallback = callback; + mLoadInitialParams = params; + mIsFetchingData.postValue(Boolean.TRUE); + + ReceiptQueryParam queryParam = new ReceiptQueryParam.Builder() + .createdAfter(mCalendarYearBeforeNow.getTime()) + .sortByCreatedOnDesc().build(); + + getHyperwallet().listPrepaidCardReceipts(mToken, queryParam, + new HyperwalletListener>() { + @Override + public void onSuccess(@Nullable HyperwalletPageList result) { + mIsFetchingData.postValue(Boolean.FALSE); + mErrors.postValue(null); + + if (result != null) { + callback.onResult(result.getDataList(), mCalendarYearBeforeNow.getTime(), null); + } + + // reset + mLoadInitialCallback = null; + mLoadInitialParams = null; + } + + @Override + public void onFailure(HyperwalletException exception) { + mIsFetchingData.postValue(Boolean.FALSE); + mErrors.postValue(new Event<>(exception.getHyperwalletErrors())); + } + + @Override + public Handler getHandler() { + return null; + } + }); + } + + /** + * @see PageKeyedDataSource#loadBefore(LoadParams, LoadCallback) + */ + @Override + public void loadBefore(@NonNull final LoadParams params, + @NonNull final LoadCallback callback) { + } + + /** + * @see PageKeyedDataSource#loadAfter(LoadParams, LoadCallback) + */ + @Override + public void loadAfter(@NonNull final LoadParams params, @NonNull final LoadCallback callback) { + mLoadAfterCallback = callback; + mLoadAfterParams = params; + mIsFetchingData.postValue(Boolean.TRUE); + + ReceiptQueryParam queryParam = new ReceiptQueryParam.Builder() + .createdAfter(params.key) + .limit(params.requestedLoadSize) + .sortByCreatedOnDesc().build(); + + getHyperwallet().listPrepaidCardReceipts(mToken, queryParam, + new HyperwalletListener>() { + @Override + public void onSuccess(@Nullable HyperwalletPageList result) { + mIsFetchingData.postValue(Boolean.FALSE); + mErrors.postValue(null); + + if (result != null) { + callback.onResult(result.getDataList(), getNextDate(result)); + } + + // reset + mLoadAfterCallback = null; + mLoadAfterParams = null; + } + + @Override + public void onFailure(HyperwalletException exception) { + mIsFetchingData.postValue(Boolean.FALSE); + mErrors.postValue(new Event<>(exception.getHyperwalletErrors())); + } + + @Override + public Handler getHandler() { + return null; + } + }); + } + + /** + * Facilitates retry when network is down; any error that we can have a retry operation + */ + void retry() { + if (mLoadInitialCallback != null) { + loadInitial(mLoadInitialParams, mLoadInitialCallback); + } else if (mLoadAfterCallback != null) { + loadAfter(mLoadAfterParams, mLoadAfterCallback); + } + } + + /** + * Retrieve reference of Hyperwallet errors inorder for consumers to observe on data changes + * + * @return Live event data of {@link HyperwalletErrors} + */ + public LiveData> getErrors() { + return mErrors; + } + + LiveData isFetchingData() { + return mIsFetchingData; + } + + Hyperwallet getHyperwallet() { + return Hyperwallet.getDefault(); + } + + private Date getNextDate(@Nullable final HyperwalletPageList result) { + if (result != null && result.getDataList() != null && !result.getDataList().isEmpty()) { + // get last receipt date + return DateUtil.fromDateTimeString( + result.getDataList().get(result.getDataList().size() - 1).getCreatedOn()); + } + return Calendar.getInstance().getTime(); + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactory.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactory.java new file mode 100644 index 000000000..71edf3f7a --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactory.java @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.repository; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.paging.DataSource; + +/** + * Data source factory for PrepaidCard receipt data source, that uses {@link DataSource.Factory} facility + */ +public class PrepaidCardReceiptDataSourceFactory extends DataSource.Factory { + + private final MutableLiveData mDataSourceMutableLiveData; + private final PrepaidCardReceiptDataSource mPrepaidCardReceiptDataSource; + + PrepaidCardReceiptDataSourceFactory(@NonNull final String token) { + super(); + mPrepaidCardReceiptDataSource = new PrepaidCardReceiptDataSource(token); + mDataSourceMutableLiveData = new MutableLiveData<>(); + mDataSourceMutableLiveData.setValue(mPrepaidCardReceiptDataSource); + } + + /** + * Returns observable members of prepaid card receipt data source + */ + LiveData getPrepaidCardReceiptDataSource() { + return mDataSourceMutableLiveData; + } + + /** + * @see DataSource.Factory#create() + */ + @NonNull + @Override + public DataSource create() { + return mPrepaidCardReceiptDataSource; + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java new file mode 100644 index 000000000..021cadcc7 --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.repository; + +import androidx.lifecycle.LiveData; +import androidx.paging.PagedList; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.viewmodel.Event; + +public interface PrepaidCardReceiptRepository { + + /** + * Load prepaid card receipts information, consumer can subscribe to receipts data changes events + * + * @return live data paged prepaid card receipts + */ + LiveData> loadPrepaidCardReceipts(); + + /** + * Loading indicator consumer can subscribe to loading of data events + * + * @return live data true if load receipt is in loading state; false otherwise + */ + LiveData isLoading(); + + /** + * Error information, consumer can subscribe of errors occur during data retrieval + * + * @return live event data list of errors if there's an error + */ + LiveData> getErrors(); + + /** + * Reload receipt information, usually invoked when error is raised after the first load and consumer opts to retry + * the last operation + */ + void retryLoadReceipt(); + +} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java new file mode 100644 index 000000000..4b5fed137 --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java @@ -0,0 +1,75 @@ +package com.hyperwallet.android.ui.receipt.repository; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.paging.LivePagedListBuilder; +import androidx.paging.PagedList; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.viewmodel.Event; + +public class PrepaidCardReceiptRepositoryImpl implements PrepaidCardReceiptRepository { + + private static final int PAGE_SIZE = 10; + private static final int INITIAL_LOAD_SIZE = 20; + + private final PrepaidCardReceiptDataSourceFactory mDataSourceFactory; + private final LiveData mReceiptDataSourceLiveData; + private LiveData> mErrorsLiveData; + private LiveData mIsFetchingData; + private LiveData> mReceiptsLiveData; + + public PrepaidCardReceiptRepositoryImpl(@NonNull final String token) { + mDataSourceFactory = new PrepaidCardReceiptDataSourceFactory(token); + mReceiptDataSourceLiveData = mDataSourceFactory.getPrepaidCardReceiptDataSource(); + } + + /** + * @see PrepaidCardReceiptRepository#loadPrepaidCardReceipts() + */ + @Override + public LiveData> loadPrepaidCardReceipts() { + if (mReceiptsLiveData == null) { + PagedList.Config config = new PagedList.Config.Builder() + .setPageSize(PAGE_SIZE) + .setEnablePlaceholders(true) + .setInitialLoadSizeHint(INITIAL_LOAD_SIZE) + .build(); + mReceiptsLiveData = new LivePagedListBuilder<>(mDataSourceFactory, config).build(); + } + return mReceiptsLiveData; + } + + /** + * @see PrepaidCardReceiptRepository#isLoading() + */ + @Override + public LiveData isLoading() { + if (mIsFetchingData == null) { + mIsFetchingData = mReceiptDataSourceLiveData.getValue().isFetchingData(); + } + return mIsFetchingData; + } + + /** + * @see PrepaidCardReceiptRepository#getErrors() + */ + @Override + public LiveData> getErrors() { + if (mErrorsLiveData == null) { + mErrorsLiveData = mReceiptDataSourceLiveData.getValue().getErrors(); + } + return mErrorsLiveData; + } + + /** + * @see PrepaidCardReceiptRepository#retryLoadReceipt() + */ + @Override + public void retryLoadReceipt() { + if (mReceiptDataSourceLiveData.getValue() != null) { + mReceiptDataSourceLiveData.getValue().retry(); + } + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactory.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactory.java deleted file mode 100644 index 8fc76d7ab..000000000 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactory.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2019 Hyperwallet Systems Inc. - * - * 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 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.receipt.repository; - -/** - * {@link ReceiptRepository} factory - */ -public class ReceiptRepositoryFactory { - - private static ReceiptRepositoryFactory sInstance; - private final ReceiptRepository mReceiptRepository; - - private ReceiptRepositoryFactory() { - mReceiptRepository = new ReceiptRepositoryImpl(); - } - - /** - * Creates context single instance of this Factory - * - * @return receipt repository factory instance - */ - public static synchronized ReceiptRepositoryFactory getInstance() { - if (sInstance == null) { - sInstance = new ReceiptRepositoryFactory(); - } - return sInstance; - } - - /** - * Clears instance of repository factory - */ - public static void clearInstance() { - sInstance = null; - } - - /** - * @return ReceiptRepository instance implementation - * */ - public ReceiptRepository getReceiptRepository() { - return mReceiptRepository; - } -} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java similarity index 91% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java index fd0c3b654..28e8ef727 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSource.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java @@ -37,10 +37,10 @@ import java.util.Calendar; /** - * ReceiptDataSource mediates communication to HW API Platform particularly on - * Receipts V3 API + * UserReceiptDataSource mediates communication to HW API Platform particularly on + * Receipts Users V3 API */ -public class ReceiptDataSource extends PageKeyedDataSource { +public class UserReceiptDataSource extends PageKeyedDataSource { private static final int YEAR_BEFORE_NOW = -1; private final Calendar mCalendarYearBeforeNow; @@ -51,14 +51,14 @@ public class ReceiptDataSource extends PageKeyedDataSource { private LoadCallback mLoadAfterCallback; private LoadParams mLoadAfterParams; - ReceiptDataSource() { + UserReceiptDataSource() { super(); mCalendarYearBeforeNow = Calendar.getInstance(); mCalendarYearBeforeNow.add(Calendar.YEAR, YEAR_BEFORE_NOW); } /** - * @see {@link PageKeyedDataSource#loadInitial(LoadInitialParams, LoadInitialCallback)} + * @see PageKeyedDataSource#loadInitial(LoadInitialParams, LoadInitialCallback) */ @Override public void loadInitial(@NonNull final LoadInitialParams params, @@ -108,18 +108,18 @@ public Handler getHandler() { /** * Unused in this case * - * @see {@link PageKeyedDataSource#loadBefore(LoadParams, LoadCallback)} + * @see PageKeyedDataSource#loadBefore(LoadParams, LoadCallback) */ @Override - public void loadBefore(@NonNull LoadParams params, - @NonNull LoadCallback callback) { + public void loadBefore(@NonNull final LoadParams params, + @NonNull final LoadCallback callback) { } /** - * @see {@link PageKeyedDataSource#loadAfter(LoadParams, LoadCallback)} + * @see PageKeyedDataSource#loadAfter(LoadParams, LoadCallback) * */ @Override - public void loadAfter(@NonNull LoadParams params, + public void loadAfter(@NonNull final LoadParams params, final @NonNull LoadCallback callback) { mLoadInitialCallback = null; mLoadInitialParams = null; diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactory.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactory.java similarity index 67% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactory.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactory.java index ca3186540..e974a0c05 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactory.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactory.java @@ -22,33 +22,33 @@ import androidx.paging.DataSource; /** - * Data source factory that uses {@link DataSource.Factory} facility + * Data source factory for User receipt data source, that uses {@link DataSource.Factory} facility */ -public class ReceiptDataSourceFactory extends DataSource.Factory { +public class UserReceiptDataSourceFactory extends DataSource.Factory { - private final MutableLiveData mDataSourceMutableLiveData; - private final ReceiptDataSource mReceiptDataSource; + private final MutableLiveData mDataSourceMutableLiveData; + private final UserReceiptDataSource mUserReceiptDataSource; - ReceiptDataSourceFactory() { + UserReceiptDataSourceFactory() { super(); - mReceiptDataSource = new ReceiptDataSource(); + mUserReceiptDataSource = new UserReceiptDataSource(); mDataSourceMutableLiveData = new MutableLiveData<>(); - mDataSourceMutableLiveData.setValue(mReceiptDataSource); + mDataSourceMutableLiveData.setValue(mUserReceiptDataSource); } /** - * Returns observable members of receipt data source + * Returns observable members of user receipt data source */ - LiveData getReceiptDataSource() { + LiveData getUserReceiptDataSource() { return mDataSourceMutableLiveData; } /** - * @see {@link DataSource.Factory#create()} + * @see DataSource.Factory#create() */ @NonNull @Override public DataSource create() { - return mReceiptDataSource; + return mUserReceiptDataSource; } } diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepository.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java similarity index 89% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepository.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java index 2db846a4f..7c72ab664 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepository.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java @@ -26,14 +26,14 @@ /** * Receipt Repository Contract */ -public interface ReceiptRepository { +public interface UserReceiptRepository { /** - * Load receipts information, consumer can subscribe to receipts data changes events + * Load user receipts information, consumer can subscribe to receipts data changes events * - * @return live data paged receipts + * @return live data paged user receipts */ - LiveData> loadReceipts(); + LiveData> loadUserReceipts(); /** * Loading indicator consumer can subscribe to loading of data events diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryImpl.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java similarity index 79% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryImpl.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java index 74fe8755d..07a8fbdb9 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryImpl.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java @@ -25,29 +25,29 @@ import com.hyperwallet.android.ui.common.viewmodel.Event; /** - * {@link ReceiptRepository} implementation + * {@link UserReceiptRepository} implementation */ -public class ReceiptRepositoryImpl implements ReceiptRepository { +public class UserReceiptRepositoryImpl implements UserReceiptRepository { private static final int PAGE_SIZE = 10; private static final int INITIAL_LOAD_SIZE = 20; - private final ReceiptDataSourceFactory mDataSourceFactory; - private final LiveData mReceiptDataSourceLiveData; + private final UserReceiptDataSourceFactory mDataSourceFactory; + private final LiveData mReceiptDataSourceLiveData; private LiveData> mErrorsLiveData; private LiveData mIsFetchingData; private LiveData> mReceiptsLiveData; - ReceiptRepositoryImpl() { - mDataSourceFactory = new ReceiptDataSourceFactory(); - mReceiptDataSourceLiveData = mDataSourceFactory.getReceiptDataSource(); + public UserReceiptRepositoryImpl() { + mDataSourceFactory = new UserReceiptDataSourceFactory(); + mReceiptDataSourceLiveData = mDataSourceFactory.getUserReceiptDataSource(); } /** - * @see {@link ReceiptRepository#loadReceipts()} + * @see UserReceiptRepository#loadUserReceipts() */ @Override - public LiveData> loadReceipts() { + public LiveData> loadUserReceipts() { if (mReceiptsLiveData == null) { PagedList.Config config = new PagedList.Config.Builder() .setPageSize(PAGE_SIZE) @@ -60,7 +60,7 @@ public LiveData> loadReceipts() { } /** - * @see {@link ReceiptRepository#isLoading()} + * @see UserReceiptRepository#isLoading() */ @Override public LiveData isLoading() { @@ -71,7 +71,7 @@ public LiveData isLoading() { } /** - * @see {@link ReceiptRepository#getErrors()} + * @see UserReceiptRepository#getErrors() * */ @Override public LiveData> getErrors() { @@ -82,7 +82,7 @@ public LiveData> getErrors() { } /** - * @see {@link ReceiptRepository#retryLoadReceipt()} + * @see UserReceiptRepository#retryLoadReceipt() * */ @Override public void retryLoadReceipt() { diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java new file mode 100644 index 000000000..b774436d4 --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java @@ -0,0 +1,143 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.view; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; + +import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; +import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.viewmodel.ListDetailNavigator; +import com.hyperwallet.android.ui.receipt.R; +import com.hyperwallet.android.ui.receipt.repository.PrepaidCardReceiptRepositoryImpl; +import com.hyperwallet.android.ui.receipt.viewmodel.ListPrepaidCardReceiptViewModel; +import com.hyperwallet.android.ui.receipt.viewmodel.ReceiptViewModel; + +import java.util.List; + +public class ListPrepaidCardReceiptActivity extends AppCompatActivity implements OnNetworkErrorCallback, + ListDetailNavigator> { + + public static final String EXTRA_PREPAID_CARD_TOKEN = "PREPAID_CARD_TOKEN"; + + private ReceiptViewModel mReceiptViewModel; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_list_prepaid_card_receipt); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + getSupportActionBar().setTitle(R.string.title_activity_receipt_list); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + String token = getIntent().getStringExtra(EXTRA_PREPAID_CARD_TOKEN); + if (TextUtils.isEmpty(token)) { + throw new IllegalArgumentException("Activity " + ListPrepaidCardReceiptActivity.class.getName() + + " requires parameter: " + EXTRA_PREPAID_CARD_TOKEN + " value"); + } + + mReceiptViewModel = ViewModelProviders.of(this, new ListPrepaidCardReceiptViewModel + .ListPrepaidCardReceiptViewModelFactory(new PrepaidCardReceiptRepositoryImpl(token))) + .get(ReceiptViewModel.class); + + mReceiptViewModel.getReceiptErrors().observe(this, new Observer>() { + @Override + public void onChanged(Event event) { + if (event != null && !event.isContentConsumed()) { + showErrorOnLoadReceipt(event.getContent().getErrors()); + } + } + }); + + mReceiptViewModel.getDetailNavigation().observe(this, new Observer>() { + @Override + public void onChanged(@NonNull final Event event) { + navigate(event); + } + }); + + if (savedInstanceState == null) { + initFragment(ListReceiptFragment.newInstance()); + } + } + + @Override + public void retry() { + FragmentManager fragmentManager = getSupportFragmentManager(); + ListReceiptFragment fragment = (ListReceiptFragment) + fragmentManager.findFragmentById(R.id.list_receipt_fragment); + + if (fragment == null) { + fragment = ListReceiptFragment.newInstance(); + } + fragment.retry(); + } + + @Override + public void navigate(@NonNull final Event event) { + if (!event.isContentConsumed()) { + Intent intent = new Intent(this, ReceiptDetailActivity.class); + intent.putExtra(ReceiptDetailActivity.EXTRA_RECEIPT, event.getContent()); + startActivity(intent); + } + } + + private void initFragment(@NonNull final Fragment fragment) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.add(R.id.list_receipt_fragment, fragment); + fragmentTransaction.commit(); + } + + private void showErrorOnLoadReceipt(@NonNull final List errors) { + FragmentManager fragmentManager = getSupportFragmentManager(); + DefaultErrorDialogFragment fragment = (DefaultErrorDialogFragment) + fragmentManager.findFragmentByTag(DefaultErrorDialogFragment.TAG); + + if (fragment == null) { + fragment = DefaultErrorDialogFragment.newInstance(errors); + } + + if (!fragment.isAdded()) { + fragment.show(fragmentManager); + } + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java index e1fd220a2..64f3611c2 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java @@ -46,7 +46,7 @@ import com.hyperwallet.android.ui.common.util.DateUtils; import com.hyperwallet.android.ui.common.view.OneClickListener; import com.hyperwallet.android.ui.receipt.R; -import com.hyperwallet.android.ui.receipt.viewmodel.ListReceiptViewModel; +import com.hyperwallet.android.ui.receipt.viewmodel.ReceiptViewModel; import java.text.DecimalFormat; import java.util.Calendar; @@ -58,13 +58,13 @@ public class ListReceiptFragment extends Fragment { private ListReceiptAdapter mListReceiptAdapter; private RecyclerView mListReceiptsView; - private ListReceiptViewModel mListReceiptViewModel; + private ReceiptViewModel mReceiptViewModel; private View mProgressBar; /** * Please don't use this constructor this is reserved for Android Core Framework * - * @see {@link ListReceiptFragment#newInstance()} instead. + * @see #newInstance() */ public ListReceiptFragment() { setRetainInstance(true); @@ -78,8 +78,8 @@ static ListReceiptFragment newInstance() { @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mListReceiptViewModel = ViewModelProviders.of(requireActivity()).get( - ListReceiptViewModel.class); + mReceiptViewModel = ViewModelProviders.of(requireActivity()).get( + ReceiptViewModel.class); } @Override @@ -92,7 +92,7 @@ public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mProgressBar = view.findViewById(R.id.list_receipt_progress_bar); - mListReceiptAdapter = new ListReceiptAdapter(mListReceiptViewModel, new ListReceiptItemDiffCallback()); + mListReceiptAdapter = new ListReceiptAdapter(mReceiptViewModel, new ListReceiptItemDiffCallback()); mListReceiptsView = view.findViewById(R.id.list_receipts); mListReceiptsView.setHasFixedSize(true); mListReceiptsView.setLayoutManager(new LinearLayoutManager(getActivity())); @@ -102,14 +102,14 @@ public void onViewCreated(@NonNull final View view, @Nullable final Bundle saved } private void registerObservers() { - mListReceiptViewModel.getReceiptList().observe(getViewLifecycleOwner(), new Observer>() { + mReceiptViewModel.getReceiptList().observe(getViewLifecycleOwner(), new Observer>() { @Override public void onChanged(PagedList receipts) { mListReceiptAdapter.submitList(receipts); } }); - mListReceiptViewModel.isLoadingData().observe(getViewLifecycleOwner(), new Observer() { + mReceiptViewModel.isLoadingData().observe(getViewLifecycleOwner(), new Observer() { @Override public void onChanged(Boolean loading) { if (loading) { @@ -122,7 +122,7 @@ public void onChanged(Boolean loading) { } void retry() { - mListReceiptViewModel.retryLoadReceipts(); + mReceiptViewModel.retryLoadReceipts(); } private static class ListReceiptItemDiffCallback extends DiffUtil.ItemCallback { @@ -146,9 +146,9 @@ private static class ListReceiptAdapter static final String AMOUNT_FORMAT = "###0.00"; private static final int HEADER_VIEW_TYPE = 1; private static final int DATA_VIEW_TYPE = 0; - private final ListReceiptViewModel mReceiptViewModel; + private final ReceiptViewModel mReceiptViewModel; - ListReceiptAdapter(@NonNull final ListReceiptViewModel receiptViewModel, + ListReceiptAdapter(@NonNull final ReceiptViewModel receiptViewModel, @NonNull final DiffUtil.ItemCallback diffCallback) { super(diffCallback); mReceiptViewModel = receiptViewModel; @@ -199,25 +199,25 @@ public void onBindViewHolder(@NonNull final ReceiptViewHolder holder, final int class ReceiptViewHolder extends RecyclerView.ViewHolder { - private ListReceiptViewModel mListReceiptViewModel; + private ReceiptViewModel mListUserReceiptViewModel; private View mView; - ReceiptViewHolder(@NonNull final ListReceiptViewModel receiptViewModel, + ReceiptViewHolder(@NonNull final ReceiptViewModel receiptViewModel, @NonNull final View item) { super(item); mView = item.findViewById(R.id.receipt_item); - mListReceiptViewModel = receiptViewModel; + mListUserReceiptViewModel = receiptViewModel; } void bind(@NonNull final Receipt receipt) { mView.setOnClickListener(new OneClickListener() { @Override public void onOneClick(View v) { - mListReceiptViewModel.setDetailNavigation(receipt); + mListUserReceiptViewModel.setDetailNavigation(receipt); } }); - // By design decision from here under, this code is also repeated in ReceiptDetailFragment + // By design decision from hereon, this code is also repeated in ReceiptDetailFragment TextView transactionTypeIcon = itemView.findViewById(R.id.transaction_type_icon); TextView transactionTitle = itemView.findViewById(R.id.transaction_title); TextView transactionDate = itemView.findViewById(R.id.transaction_date); @@ -274,8 +274,7 @@ class ReceiptViewHolderWithHeader extends ReceiptViewHolder { private final TextView mTransactionHeaderText; - ReceiptViewHolderWithHeader(@NonNull final ListReceiptViewModel receiptViewModel, - @NonNull final View item) { + ReceiptViewHolderWithHeader(@NonNull final ReceiptViewModel receiptViewModel, @NonNull final View item) { super(receiptViewModel, item); mTransactionHeaderText = item.findViewById(R.id.item_date_header_title); } diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java similarity index 83% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java index ef56fa89b..bc66e9609 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptActivity.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java @@ -38,20 +38,21 @@ import com.hyperwallet.android.ui.common.viewmodel.Event; import com.hyperwallet.android.ui.common.viewmodel.ListDetailNavigator; import com.hyperwallet.android.ui.receipt.R; -import com.hyperwallet.android.ui.receipt.repository.ReceiptRepositoryFactory; -import com.hyperwallet.android.ui.receipt.viewmodel.ListReceiptViewModel; +import com.hyperwallet.android.ui.receipt.repository.UserReceiptRepositoryImpl; +import com.hyperwallet.android.ui.receipt.viewmodel.ListUserReceiptViewModel; +import com.hyperwallet.android.ui.receipt.viewmodel.ReceiptViewModel; import java.util.List; -public class ListReceiptActivity extends AppCompatActivity implements OnNetworkErrorCallback, +public class ListUserReceiptActivity extends AppCompatActivity implements OnNetworkErrorCallback, ListDetailNavigator> { - private ListReceiptViewModel mListReceiptViewModel; + private ReceiptViewModel mReceiptViewModel; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_list_receipt); + setContentView(R.layout.activity_list_user_receipt); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); @@ -65,12 +66,11 @@ public void onClick(View v) { } }); - ReceiptRepositoryFactory factory = ReceiptRepositoryFactory.getInstance(); - mListReceiptViewModel = ViewModelProviders.of(this, new ListReceiptViewModel - .ListReceiptViewModelFactory(factory.getReceiptRepository())) - .get(ListReceiptViewModel.class); + mReceiptViewModel = ViewModelProviders.of(this, new ListUserReceiptViewModel + .ListReceiptViewModelFactory(new UserReceiptRepositoryImpl())) + .get(ReceiptViewModel.class); - mListReceiptViewModel.getReceiptErrors().observe(this, new Observer>() { + mReceiptViewModel.getReceiptErrors().observe(this, new Observer>() { @Override public void onChanged(Event event) { if (event != null && !event.isContentConsumed()) { @@ -79,7 +79,7 @@ public void onChanged(Event event) { } }); - mListReceiptViewModel.getDetailNavigation().observe(this, new Observer>() { + mReceiptViewModel.getDetailNavigation().observe(this, new Observer>() { @Override public void onChanged(Event event) { navigate(event); @@ -91,12 +91,6 @@ public void onChanged(Event event) { } } - @Override - protected void onDestroy() { - super.onDestroy(); - ReceiptRepositoryFactory.clearInstance(); - } - @Override protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) { super.onActivityResult(requestCode, resultCode, data); diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java index 8e8f99dec..7c9a349b1 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java @@ -52,8 +52,8 @@ public class ReceiptDetailFragment extends Fragment { - static final String AMOUNT_FORMAT = "###0.00"; - static final String DETAIL_TIMEZONE = "zzz"; + private static final String AMOUNT_FORMAT = "###0.00"; + private static final String DETAIL_TIMEZONE = "zzz"; private ReceiptDetailViewModel mReceiptDetailViewModel; diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java new file mode 100644 index 000000000..73f697bca --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java @@ -0,0 +1,130 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.viewmodel; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; +import androidx.paging.PagedList; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.receipt.repository.PrepaidCardReceiptRepository; + +public class ListPrepaidCardReceiptViewModel extends ReceiptViewModel { + + private MutableLiveData> mErrorEvent = new MutableLiveData<>(); + private MutableLiveData> mDetailNavigation = new MutableLiveData<>(); + private Observer> mErrorEventObserver; + private PrepaidCardReceiptRepository mPrepaidCardReceiptRepository; + + private ListPrepaidCardReceiptViewModel(@NonNull final PrepaidCardReceiptRepository receiptRepository) { + mPrepaidCardReceiptRepository = receiptRepository; + // load initial receipts + mPrepaidCardReceiptRepository.loadPrepaidCardReceipts(); + + // register one time error event observer + mErrorEventObserver = new Observer>() { + @Override + public void onChanged(Event event) { + mErrorEvent.postValue(event); + } + }; + mPrepaidCardReceiptRepository.getErrors().observeForever(mErrorEventObserver); + } + + /** + * @see ReceiptViewModel#isLoadingData() + */ + @Override + public LiveData isLoadingData() { + return mPrepaidCardReceiptRepository.isLoading(); + } + + /** + * @see ReceiptViewModel#getReceiptErrors() + */ + @Override + public LiveData> getReceiptErrors() { + return mErrorEvent; + } + + /** + * @see ReceiptViewModel#getReceiptList() + */ + @Override + public LiveData> getReceiptList() { + return mPrepaidCardReceiptRepository.loadPrepaidCardReceipts(); + } + + /** + * @see ReceiptViewModel#retryLoadReceipts() + */ + @Override + public void retryLoadReceipts() { + mPrepaidCardReceiptRepository.retryLoadReceipt(); + } + + /** + * @see ReceiptViewModel#getDetailNavigation() + */ + @Override + public LiveData> getDetailNavigation() { + return mDetailNavigation; + } + + /** + * @see ReceiptViewModel#setDetailNavigation(Receipt) + */ + @Override + public void setDetailNavigation(@NonNull Receipt receipt) { + mDetailNavigation.postValue(new Event<>(receipt)); + } + + /** + * @see ViewModel#onCleared() + */ + @Override + protected void onCleared() { + super.onCleared(); + mPrepaidCardReceiptRepository.getErrors().removeObserver(mErrorEventObserver); + mPrepaidCardReceiptRepository = null; + } + + public static class ListPrepaidCardReceiptViewModelFactory implements ViewModelProvider.Factory { + + private final PrepaidCardReceiptRepository mPrepaidCardReceiptRepository; + + public ListPrepaidCardReceiptViewModelFactory(@NonNull final PrepaidCardReceiptRepository repository) { + mPrepaidCardReceiptRepository = repository; + } + + @NonNull + @Override + public T create(@NonNull final Class modelClass) { + if (modelClass.isAssignableFrom(ListUserReceiptViewModel.class)) { + return (T) new ListPrepaidCardReceiptViewModel(mPrepaidCardReceiptRepository); + } + throw new IllegalArgumentException( + "Expecting ViewModel class: " + ListPrepaidCardReceiptViewModel.class.getName()); + } + } +} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java similarity index 62% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java rename to receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java index 0d1533a58..9b9b63b2c 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListReceiptViewModel.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java @@ -27,19 +27,19 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.ui.common.viewmodel.Event; -import com.hyperwallet.android.ui.receipt.repository.ReceiptRepository; +import com.hyperwallet.android.ui.receipt.repository.UserReceiptRepository; -public class ListReceiptViewModel extends ViewModel { +public class ListUserReceiptViewModel extends ReceiptViewModel { private MutableLiveData> mErrorEvent = new MutableLiveData<>(); private MutableLiveData> mDetailNavigation = new MutableLiveData<>(); private Observer> mErrorEventObserver; - private ReceiptRepository mReceiptRepository; + private UserReceiptRepository mUserReceiptRepository; - private ListReceiptViewModel(@NonNull final ReceiptRepository receiptRepository) { - mReceiptRepository = receiptRepository; + private ListUserReceiptViewModel(@NonNull final UserReceiptRepository userReceiptRepository) { + mUserReceiptRepository = userReceiptRepository; // load initial receipts - mReceiptRepository.loadReceipts(); + mUserReceiptRepository.loadUserReceipts(); // register one time error event observer mErrorEventObserver = new Observer>() { @@ -48,55 +48,77 @@ public void onChanged(Event event) { mErrorEvent.postValue(event); } }; - mReceiptRepository.getErrors().observeForever(mErrorEventObserver); + mUserReceiptRepository.getErrors().observeForever(mErrorEventObserver); } + /** + * @see ReceiptViewModel#isLoadingData() + */ public LiveData isLoadingData() { - return mReceiptRepository.isLoading(); + return mUserReceiptRepository.isLoading(); } + /** + * @see ReceiptViewModel#getReceiptErrors() + */ public LiveData> getReceiptErrors() { return mErrorEvent; } + /** + * @see ReceiptViewModel#getReceiptList() + */ public LiveData> getReceiptList() { - return mReceiptRepository.loadReceipts(); + return mUserReceiptRepository.loadUserReceipts(); } + /** + * @see ReceiptViewModel#retryLoadReceipts() + * */ public void retryLoadReceipts() { - mReceiptRepository.retryLoadReceipt(); + mUserReceiptRepository.retryLoadReceipt(); } + /** + * @see ReceiptViewModel#getDetailNavigation() + * */ public LiveData> getDetailNavigation() { return mDetailNavigation; } + /** + * @see ReceiptViewModel#setDetailNavigation(Receipt) + * */ public void setDetailNavigation(@NonNull final Receipt receipt) { mDetailNavigation.postValue(new Event<>(receipt)); } + /** + * @see ViewModel#onCleared() + * */ @Override protected void onCleared() { super.onCleared(); - mReceiptRepository.getErrors().removeObserver(mErrorEventObserver); - mReceiptRepository = null; + mUserReceiptRepository.getErrors().removeObserver(mErrorEventObserver); + mUserReceiptRepository = null; } public static class ListReceiptViewModelFactory implements ViewModelProvider.Factory { - private final ReceiptRepository mReceiptRepository; + private final UserReceiptRepository mUserReceiptRepository; - public ListReceiptViewModelFactory(@NonNull final ReceiptRepository receiptRepository) { - mReceiptRepository = receiptRepository; + public ListReceiptViewModelFactory(@NonNull final UserReceiptRepository userReceiptRepository) { + mUserReceiptRepository = userReceiptRepository; } @NonNull @Override public T create(@NonNull Class modelClass) { - if (modelClass.isAssignableFrom(ListReceiptViewModel.class)) { - return (T) new ListReceiptViewModel(mReceiptRepository); + if (modelClass.isAssignableFrom(ListUserReceiptViewModel.class)) { + return (T) new ListUserReceiptViewModel(mUserReceiptRepository); } - throw new IllegalArgumentException("Expecting ViewModel class: " + ListReceiptViewModel.class.getName()); + throw new IllegalArgumentException( + "Expecting ViewModel class: " + ListUserReceiptViewModel.class.getName()); } } } diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java new file mode 100644 index 000000000..f100b86bc --- /dev/null +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.receipt.viewmodel; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.ViewModel; +import androidx.paging.PagedList; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.viewmodel.Event; + +public abstract class ReceiptViewModel extends ViewModel { + + /** + * @return live data of isloading information + */ + public abstract LiveData isLoadingData(); + + /** + * @return live data of receipt errors {@link HyperwalletErrors} + */ + public abstract LiveData> getReceiptErrors(); + + /** + * @return paged live data of receipts {@link Receipt} + */ + public abstract LiveData> getReceiptList(); + + /** + * Explicit invoke of load retry on receipts data + */ + public abstract void retryLoadReceipts(); + + /** + * @return binding live data of detail navigation information + */ + public abstract LiveData> getDetailNavigation(); + + /** + * @param receipt {@link Receipt} object to set on navigating to Receipt details view + */ + public abstract void setDetailNavigation(@NonNull final Receipt receipt); +} diff --git a/receipt/src/main/res/layout/activity_list_prepaid_card_receipt.xml b/receipt/src/main/res/layout/activity_list_prepaid_card_receipt.xml new file mode 100644 index 000000000..03376549f --- /dev/null +++ b/receipt/src/main/res/layout/activity_list_prepaid_card_receipt.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/receipt/src/main/res/layout/activity_list_receipt.xml b/receipt/src/main/res/layout/activity_list_user_receipt.xml similarity index 91% rename from receipt/src/main/res/layout/activity_list_receipt.xml rename to receipt/src/main/res/layout/activity_list_user_receipt.xml index 44beb1444..2eb8c57ac 100644 --- a/receipt/src/main/res/layout/activity_list_receipt.xml +++ b/receipt/src/main/res/layout/activity_list_user_receipt.xml @@ -5,7 +5,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".view.ListReceiptActivity"> + tools:context=".view.ListUserReceiptActivity"> + tools:context=".view.ListUserReceiptActivity" + tools:showIn="@layout/activity_list_user_receipt"/> \ No newline at end of file diff --git a/receipt/src/main/res/layout/fragment_list_receipt.xml b/receipt/src/main/res/layout/fragment_list_receipt.xml index 52e9725db..f6463cf45 100644 --- a/receipt/src/main/res/layout/fragment_list_receipt.xml +++ b/receipt/src/main/res/layout/fragment_list_receipt.xml @@ -23,4 +23,29 @@ android:indeterminate="true" android:theme="@style/Widget.Hyperwallet.ProgressBar.Receipts"/> + + + + + + + + \ No newline at end of file diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactoryTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactoryTest.java new file mode 100644 index 000000000..30a2e35e4 --- /dev/null +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactoryTest.java @@ -0,0 +1,38 @@ +package com.hyperwallet.android.ui.receipt.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; + +import androidx.lifecycle.LiveData; +import androidx.paging.DataSource; + +import org.hamcrest.CoreMatchers; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class PrepaidCardReceiptDataSourceFactoryTest { + + @Test + public void testGetReceiptDataSource_returnsLiveDataReceiptSource() { + // initialize + PrepaidCardReceiptDataSourceFactory dataSourceFactory = new PrepaidCardReceiptDataSourceFactory("token"); + // test + LiveData liveData = dataSourceFactory.getPrepaidCardReceiptDataSource(); + // assert + assertThat(liveData, is(notNullValue())); + } + + @Test + public void testCreate_returnsDataSource() { + // initialize + PrepaidCardReceiptDataSourceFactory dataSourceFactory = new PrepaidCardReceiptDataSourceFactory("token"); + // test + DataSource dataSource = dataSourceFactory.create(); + // assert + assertThat(dataSource, is(notNullValue())); + assertThat(dataSource, CoreMatchers.instanceOf(PrepaidCardReceiptDataSource.class)); + } +} diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java new file mode 100644 index 000000000..f703e7810 --- /dev/null +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java @@ -0,0 +1,396 @@ +package com.hyperwallet.android.ui.receipt.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import static com.hyperwallet.android.model.receipt.Receipt.Entries.CREDIT; +import static com.hyperwallet.android.model.receipt.Receipt.ReceiptTypes.ADJUSTMENT; +import static com.hyperwallet.android.model.receipt.Receipt.ReceiptTypes.DEPOSIT; + +import androidx.paging.PageKeyedDataSource; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.listener.HyperwalletListener; +import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.paging.HyperwalletPageList; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.model.receipt.ReceiptQueryParam; +import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.util.DateUtil; + +import org.hamcrest.Matchers; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.stubbing.Answer; +import org.robolectric.RobolectricTestRunner; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class PrepaidCardReceiptDataSourceTest { + + @Rule + public MockitoRule mMockito = MockitoJUnit.rule(); + @Rule + public HyperwalletExternalResourceManager mExternalResourceManager = new HyperwalletExternalResourceManager(); + + @Mock + private Hyperwallet mHyperwallet; + @Mock + private PageKeyedDataSource.LoadInitialParams mInitialParams; + @Mock + private PageKeyedDataSource.LoadInitialCallback mInitialCallback; + // can't be mocked due to params.key is of type Integer and autoboxing will not work with null to 0 + private final PageKeyedDataSource.LoadParams mLoadAfterParams = new PageKeyedDataSource.LoadParams<>( + new Date(), 10); + @Mock + private PageKeyedDataSource.LoadCallback mLoadAfterCallback; + + @Captor + private ArgumentCaptor> mListArgumentCaptor; + @Captor + private ArgumentCaptor mPreviousCaptor; + @Captor + private ArgumentCaptor mNextCaptor; + + private PrepaidCardReceiptDataSource mPrepaidCardReceiptDataSource; + + @Before + public void setUp() { + mPrepaidCardReceiptDataSource = spy(new PrepaidCardReceiptDataSource("test-token")); + doReturn(mHyperwallet).when(mPrepaidCardReceiptDataSource).getHyperwallet(); + } + + + @Test + public void testLoadInitial_returnsReceipts() throws Exception { + String json = mExternalResourceManager.getResourceContent("prepaid_card_receipt_list.json"); + JSONObject jsonObject = new JSONObject(json); + final HyperwalletPageList response = new HyperwalletPageList<>(jsonObject, Receipt.class); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onSuccess(response); + return listener; + } + }).when(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mPrepaidCardReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + + // verify + verify(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mInitialCallback).onResult(mListArgumentCaptor.capture(), mPreviousCaptor.capture(), + mNextCaptor.capture()); + + assertThat(mPreviousCaptor.getValue(), is(notNullValue())); + assertThat(mNextCaptor.getValue(), is(nullValue())); + + // assert receipts information + List receipts = mListArgumentCaptor.getValue(); + assertThat(receipts, Matchers.hasSize(7)); + assertThat(receipts.get(0).getJournalId(), is("FISVL_5240220")); + assertThat(receipts.get(0).getType(), is(DEPOSIT)); + assertThat(receipts.get(0).getCreatedOn(), is("2019-06-06T22:48:41")); + assertThat(receipts.get(0).getEntry(), is(CREDIT)); + assertThat(receipts.get(0).getDestinationToken(), is("trm-2e02da75-a36c-4723-b613-0b64e6f582d9")); + assertThat(receipts.get(0).getAmount(), is("10.00")); + assertThat(receipts.get(0).getCurrency(), is("USD")); + assertThat(receipts.get(0).getDetails(), is(notNullValue())); + assertThat(receipts.get(0).getDetails().getCardNumber(), is("************0673")); + assertThat(receipts.get(6).getJournalId(), is("FISA_5240226")); + assertThat(receipts.get(6).getType(), is(ADJUSTMENT)); + assertThat(receipts.get(6).getCreatedOn(), is("2019-02-21T23:55:17")); + assertThat(receipts.get(6).getEntry(), is(CREDIT)); + assertThat(receipts.get(6).getSourceToken(), is("trm-2e02da75-a36c-4723-b613-0b64e6f582d9")); + assertThat(receipts.get(6).getAmount(), is("9.92")); + assertThat(receipts.get(6).getCurrency(), is("USD")); + assertThat(receipts.get(6).getDetails(), is(notNullValue())); + assertThat(receipts.get(6).getDetails().getCardNumber(), is("************0673")); + + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue(), is(Matchers.nullValue())); + assertThat(mPrepaidCardReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testLoadInitial_returnNoReceipt() { + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onSuccess(null); + return listener; + } + }).when(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mPrepaidCardReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + + // verify + verify(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), any(Date.class), + any(Date.class)); + + // assert + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue(), is(Matchers.nullValue())); + assertThat(mPrepaidCardReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testLoadInitial_withError() { + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + List errorList = new ArrayList<>(); + errorList.add(error); + final HyperwalletErrors errors = new HyperwalletErrors(errorList); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mPrepaidCardReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + + // verify + verify(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), any(Date.class), + any(Date.class)); + + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue(), is(notNullValue())); + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue().getContent().getErrors(), + Matchers.hasSize(1)); + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getCode(), + is("TEST_CODE")); + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getMessage(), + is("test message")); + assertThat(mPrepaidCardReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testRetry_loadInitial() { + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + List errorList = new ArrayList<>(); + errorList.add(error); + final HyperwalletErrors errors = new HyperwalletErrors(errorList); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mPrepaidCardReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + + // verify + verify(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), any(Date.class), + any(Date.class)); + + // error occurred, this will save params and callback + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue(), is(notNullValue())); + + // test retry + mPrepaidCardReceiptDataSource.retry(); + + // verify calls + verify(mPrepaidCardReceiptDataSource, times(2)).loadInitial( + ArgumentMatchers.>any(), + ArgumentMatchers.>any()); + verify(mPrepaidCardReceiptDataSource, never()).loadAfter( + ArgumentMatchers.>any(), + ArgumentMatchers.>any()); + } + + @Test + public void testLoadAfter_returnsReceipts() throws Exception { + String json = mExternalResourceManager.getResourceContent("prepaid_card_receipt_list.json"); + JSONObject jsonObject = new JSONObject(json); + final HyperwalletPageList response = new HyperwalletPageList<>(jsonObject, Receipt.class); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onSuccess(response); + return listener; + } + }).when(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mPrepaidCardReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + + // verify + verify(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mLoadAfterCallback).onResult(mListArgumentCaptor.capture(), mNextCaptor.capture()); + + // assert receipts information + List receipts = mListArgumentCaptor.getValue(); + assertThat(receipts, Matchers.hasSize(7)); + assertThat(receipts.get(1).getJournalId(), is("FISVL_5240221")); + assertThat(receipts.get(1).getType(), is(DEPOSIT)); + assertThat(receipts.get(1).getCreatedOn(), is("2019-06-06T22:48:51")); + assertThat(receipts.get(1).getEntry(), is(CREDIT)); + assertThat(receipts.get(1).getDestinationToken(), is("trm-2e02da75-a36c-4723-b613-0b64e6f582d9")); + assertThat(receipts.get(1).getAmount(), is("5.00")); + assertThat(receipts.get(1).getCurrency(), is("USD")); + assertThat(receipts.get(1).getDetails(), is(notNullValue())); + assertThat(receipts.get(1).getDetails().getCardNumber(), is("************0673")); + assertThat(receipts.get(5).getJournalId(), is("FISA_5240225")); + assertThat(receipts.get(5).getType(), is(ADJUSTMENT)); + assertThat(receipts.get(5).getCreatedOn(), is("2019-02-23T23:55:17")); + assertThat(receipts.get(5).getEntry(), is(CREDIT)); + assertThat(receipts.get(5).getSourceToken(), is("trm-2e02da75-a36c-4723-b613-0b64e6f582d9")); + assertThat(receipts.get(5).getAmount(), is("3.90")); + assertThat(receipts.get(5).getCurrency(), is("USD")); + assertThat(receipts.get(5).getDetails(), is(notNullValue())); + assertThat(receipts.get(5).getDetails().getCardNumber(), is("************0673")); + + assertThat(mNextCaptor.getValue(), is(DateUtil.fromDateTimeString(receipts.get(6).getCreatedOn()))); + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue(), is(Matchers.nullValue())); + assertThat(mPrepaidCardReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testLoadAfter_returnNoReceipt() { + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onSuccess(null); + return listener; + } + }).when(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mPrepaidCardReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + + // verify + verify(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.anyList(), any(Date.class)); + + // assert + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue(), is(Matchers.nullValue())); + assertThat(mPrepaidCardReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testLoadAfter_withError() { + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + List errorList = new ArrayList<>(); + errorList.add(error); + final HyperwalletErrors errors = new HyperwalletErrors(errorList); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mPrepaidCardReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + + // verify + verify(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.anyList(), any(Date.class)); + + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue(), is(notNullValue())); + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue().getContent().getErrors(), + Matchers.hasSize(1)); + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getCode(), + is("TEST_CODE")); + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getMessage(), + is("test message")); + assertThat(mPrepaidCardReceiptDataSource.isFetchingData().getValue(), is(false)); + } + + @Test + public void testRetry_loadAfter() { + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + List errorList = new ArrayList<>(); + errorList.add(error); + final HyperwalletErrors errors = new HyperwalletErrors(errorList); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + + // test + mPrepaidCardReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + + // verify + verify(mHyperwallet).listPrepaidCardReceipts(anyString(), any(ReceiptQueryParam.class), + ArgumentMatchers.>>any()); + verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.anyList(), any(Date.class)); + + // error occurred, this will save params and callback + assertThat(mPrepaidCardReceiptDataSource.getErrors().getValue(), is(notNullValue())); + + // test retry + mPrepaidCardReceiptDataSource.retry(); + + // verify calls + verify(mPrepaidCardReceiptDataSource, never()).loadInitial( + ArgumentMatchers.>any(), + ArgumentMatchers.>any()); + verify(mPrepaidCardReceiptDataSource, times(2)).loadAfter( + ArgumentMatchers.>any(), + ArgumentMatchers.>any()); + } +} diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactoryTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactoryTest.java deleted file mode 100644 index 714becb62..000000000 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryFactoryTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.hyperwallet.android.ui.receipt.repository; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.notNullValue; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -@RunWith(RobolectricTestRunner.class) -public class ReceiptRepositoryFactoryTest { - - @Test - public void testGetInstance_verifyRepositoriesInitialized() { - // test - ReceiptRepositoryFactory factory = ReceiptRepositoryFactory.getInstance(); - assertThat(factory, is(notNullValue())); - assertThat(factory.getReceiptRepository(), is(notNullValue())); - - ReceiptRepositoryFactory factory2 = ReceiptRepositoryFactory.getInstance(); - assertThat(factory, is(factory2)); - assertThat(factory.getReceiptRepository(), is(factory2.getReceiptRepository())); - } - - @Test - public void testClearInstance_verifyRepositoriesCleared() { - ReceiptRepositoryFactory factory = ReceiptRepositoryFactory.getInstance(); - assertThat(factory, is(notNullValue())); - assertThat(factory.getReceiptRepository(), is(notNullValue())); - - // test clear - ReceiptRepositoryFactory.clearInstance(); - ReceiptRepositoryFactory factory2 = ReceiptRepositoryFactory.getInstance(); - assertThat(factory, is(not(factory2))); - assertThat(factory.getReceiptRepository(), is(not(factory2.getReceiptRepository()))); - } -} diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactoryTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactoryTest.java similarity index 72% rename from receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactoryTest.java rename to receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactoryTest.java index b8a6974f2..feb62a3a2 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceFactoryTest.java +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactoryTest.java @@ -13,14 +13,14 @@ import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) -public class ReceiptDataSourceFactoryTest { +public class UserReceiptDataSourceFactoryTest { @Test public void testGetReceiptDataSource_returnsLiveDataReceiptSource() { // initialize - ReceiptDataSourceFactory dataSourceFactory = new ReceiptDataSourceFactory(); + UserReceiptDataSourceFactory dataSourceFactory = new UserReceiptDataSourceFactory(); // test - LiveData liveData = dataSourceFactory.getReceiptDataSource(); + LiveData liveData = dataSourceFactory.getUserReceiptDataSource(); // assert assertThat(liveData, is(notNullValue())); } @@ -28,11 +28,11 @@ public void testGetReceiptDataSource_returnsLiveDataReceiptSource() { @Test public void testCreate_returnsDataSource() { // initialize - ReceiptDataSourceFactory dataSourceFactory = new ReceiptDataSourceFactory(); + UserReceiptDataSourceFactory dataSourceFactory = new UserReceiptDataSourceFactory(); // test DataSource dataSource = dataSourceFactory.create(); // assert assertThat(dataSource, is(notNullValue())); - assertThat(dataSource, CoreMatchers.instanceOf(ReceiptDataSource.class)); + assertThat(dataSource, CoreMatchers.instanceOf(UserReceiptDataSource.class)); } } diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java similarity index 85% rename from receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java rename to receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java index 50aa0ad5e..e61646e32 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/ReceiptDataSourceTest.java +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java @@ -50,7 +50,7 @@ import java.util.List; @RunWith(RobolectricTestRunner.class) -public class ReceiptDataSourceTest { +public class UserReceiptDataSourceTest { @Rule public MockitoRule mMockito = MockitoJUnit.rule(); @@ -77,11 +77,11 @@ public class ReceiptDataSourceTest { private ArgumentCaptor mNextCaptor; @Spy - private ReceiptDataSource mReceiptDataSource; + private UserReceiptDataSource mUserReceiptDataSource; @Before public void setUp() { - doReturn(mHyperwallet).when(mReceiptDataSource).getHyperwallet(); + doReturn(mHyperwallet).when(mUserReceiptDataSource).getHyperwallet(); } @Test @@ -100,7 +100,7 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>>any()); // test - mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + mUserReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); @@ -136,8 +136,8 @@ public Object answer(InvocationOnMock invocation) { assertThat(receipts.get(1).getDetails().getPayeeName(), is("Kevin Puckett")); assertThat(receipts.get(1).getDetails().getBankAccountId(), is("patzachery.mcclary@example.com")); - assertThat(mReceiptDataSource.getErrors().getValue(), is(nullValue())); - assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + assertThat(mUserReceiptDataSource.getErrors().getValue(), is(nullValue())); + assertThat(mUserReceiptDataSource.isFetchingData().getValue(), is(false)); } @Test @@ -153,14 +153,14 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>>any()); // test - mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + mUserReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt(), anyInt()); - assertThat(mReceiptDataSource.getErrors().getValue(), is(nullValue())); - assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + assertThat(mUserReceiptDataSource.getErrors().getValue(), is(nullValue())); + assertThat(mUserReceiptDataSource.isFetchingData().getValue(), is(false)); } @Test @@ -181,20 +181,20 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>>any()); // test - mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + mUserReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt(), anyInt()); - assertThat(mReceiptDataSource.getErrors().getValue(), is(notNullValue())); - assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors(), + assertThat(mUserReceiptDataSource.getErrors().getValue(), is(notNullValue())); + assertThat(mUserReceiptDataSource.getErrors().getValue().getContent().getErrors(), Matchers.hasSize(1)); - assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getCode(), + assertThat(mUserReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getCode(), is("TEST_CODE")); - assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getMessage(), + assertThat(mUserReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getMessage(), is("test message")); - assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + assertThat(mUserReceiptDataSource.isFetchingData().getValue(), is(false)); } @Test @@ -215,23 +215,23 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>>any()); // test - mReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); + mUserReceiptDataSource.loadInitial(mInitialParams, mInitialCallback); verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mInitialCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt(), anyInt()); // error occurred, this will save params and callback - assertThat(mReceiptDataSource.getErrors().getValue(), is(notNullValue())); + assertThat(mUserReceiptDataSource.getErrors().getValue(), is(notNullValue())); // test retry, saved params and callback will be used and no null pointer exception is thrown - mReceiptDataSource.retry(); + mUserReceiptDataSource.retry(); // verify calls - verify(mReceiptDataSource, times(2)).loadInitial( + verify(mUserReceiptDataSource, times(2)).loadInitial( ArgumentMatchers.>any(), ArgumentMatchers.>any()); - verify(mReceiptDataSource, never()).loadAfter( + verify(mUserReceiptDataSource, never()).loadAfter( ArgumentMatchers.>any(), ArgumentMatchers.>any()); } @@ -252,7 +252,7 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>>any()); // test - mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + mUserReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); @@ -286,8 +286,8 @@ public Object answer(InvocationOnMock invocation) { assertThat(receipts.get(4).getDetails().getPayeeName(), is("Kevin Puckett")); assertThat(receipts.get(4).getDetails().getClientPaymentId(), is("wUOdfLlJONacbdHlAHOAXQT7uwX7LTPy")); - assertThat(mReceiptDataSource.getErrors().getValue(), is(nullValue())); - assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + assertThat(mUserReceiptDataSource.getErrors().getValue(), is(nullValue())); + assertThat(mUserReceiptDataSource.isFetchingData().getValue(), is(false)); } @Test @@ -303,14 +303,14 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>>any()); // test - mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + mUserReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.>any(), anyInt()); - assertThat(mReceiptDataSource.getErrors().getValue(), is(nullValue())); - assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + assertThat(mUserReceiptDataSource.getErrors().getValue(), is(nullValue())); + assertThat(mUserReceiptDataSource.isFetchingData().getValue(), is(false)); } @Test @@ -331,21 +331,21 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>>any()); // test - mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + mUserReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt()); // error occurred, this will save params and callback - assertThat(mReceiptDataSource.getErrors().getValue(), is(notNullValue())); - assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors(), + assertThat(mUserReceiptDataSource.getErrors().getValue(), is(notNullValue())); + assertThat(mUserReceiptDataSource.getErrors().getValue().getContent().getErrors(), Matchers.hasSize(1)); - assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getCode(), + assertThat(mUserReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getCode(), is("LOAD_AFTER_CODE")); - assertThat(mReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getMessage(), + assertThat(mUserReceiptDataSource.getErrors().getValue().getContent().getErrors().get(0).getMessage(), is("test message load after")); - assertThat(mReceiptDataSource.isFetchingData().getValue(), is(false)); + assertThat(mUserReceiptDataSource.isFetchingData().getValue(), is(false)); } @Test @@ -366,23 +366,23 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>>any()); // test - mReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); + mUserReceiptDataSource.loadAfter(mLoadAfterParams, mLoadAfterCallback); verify(mHyperwallet).listUserReceipts(any(ReceiptQueryParam.class), ArgumentMatchers.>>any()); verify(mLoadAfterCallback, never()).onResult(ArgumentMatchers.anyList(), anyInt()); // error occurred, this will save params and callback - assertThat(mReceiptDataSource.getErrors().getValue(), is(notNullValue())); + assertThat(mUserReceiptDataSource.getErrors().getValue(), is(notNullValue())); // test retry, saved params and callback will be used and no null pointer exception is thrown - mReceiptDataSource.retry(); + mUserReceiptDataSource.retry(); // verify calls - verify(mReceiptDataSource, times(2)).loadAfter( + verify(mUserReceiptDataSource, times(2)).loadAfter( ArgumentMatchers.>any(), ArgumentMatchers.>any()); - verify(mReceiptDataSource, never()).loadInitial( + verify(mUserReceiptDataSource, never()).loadInitial( ArgumentMatchers.>any(), ArgumentMatchers.>any()); } diff --git a/receipt/src/test/resources/prepaid_card_receipt_list.json b/receipt/src/test/resources/prepaid_card_receipt_list.json new file mode 100644 index 000000000..95715bb7a --- /dev/null +++ b/receipt/src/test/resources/prepaid_card_receipt_list.json @@ -0,0 +1,96 @@ +{ + "data": [ + { + "journalId": "FISVL_5240220", + "type": "DEPOSIT", + "createdOn": "2019-06-06T22:48:41", + "entry": "CREDIT", + "destinationToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "10.00", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISVL_5240221", + "type": "DEPOSIT", + "createdOn": "2019-06-06T22:48:51", + "entry": "CREDIT", + "destinationToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "5.00", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240222", + "type": "ADJUSTMENT", + "createdOn": "2019-06-06T22:49:17", + "entry": "DEBIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "8.90", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240223", + "type": "ADJUSTMENT", + "createdOn": "2019-03-31T23:55:17", + "entry": "DEBIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "7.90", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240224", + "type": "ADJUSTMENT", + "createdOn": "2019-02-28T23:55:17", + "entry": "CREDIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "6.90", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240225", + "type": "ADJUSTMENT", + "createdOn": "2019-02-23T23:55:17", + "entry": "CREDIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "3.90", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240226", + "type": "ADJUSTMENT", + "createdOn": "2019-02-21T23:55:17", + "entry": "CREDIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "9.92", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-e17ae43b-284d-4198-9585-f417943c624f/prepaid-cards/trm-2e02da75-a36c-4723-b613-0b64e6f582d9/receipts" + } + ] +} \ No newline at end of file diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java index fc567b50e..01e3e1d29 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java @@ -413,7 +413,7 @@ public void onReceive(Context context, Intent intent) { } @Test - public void testListTransferMethod_removeBankAccountClickCancel() throws InterruptedException { + public void testListTransferMethod_removeBankAccountClickCancel() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("transfer_method_list_response.json")).mock(); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java index b47c1f87d..21e5ac913 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java @@ -19,6 +19,7 @@ package com.hyperwallet.android.ui; +import static com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity.EXTRA_PREPAID_CARD_TOKEN; import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_COUNTRY; import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY; import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE; @@ -31,7 +32,8 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; -import com.hyperwallet.android.ui.receipt.view.ListReceiptActivity; +import com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity; +import com.hyperwallet.android.ui.receipt.view.ListUserReceiptActivity; import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; import com.hyperwallet.android.ui.transfermethod.ListTransferMethodActivity; import com.hyperwallet.android.ui.transfermethod.SelectTransferMethodActivity; @@ -81,10 +83,20 @@ public Intent getIntentSelectTransferMethodActivity(@NonNull final Context conte /** * @param context A Context of the application consuming this Intent. - * @return an Intent with the data necessary to launch the {@link ListReceiptActivity} + * @return an Intent with the data necessary to launch the {@link ListUserReceiptActivity} */ - public Intent getIntentListReceiptActivity(@NonNull final Context context) { - return new Intent(context, ListReceiptActivity.class); + public Intent getIntentListUserReceiptActivity(@NonNull final Context context) { + return new Intent(context, ListUserReceiptActivity.class); + } + + /** + * @param context A Context of the application consuming this Intent. + * @return an Intent with the data necessary to launch the {@link ListPrepaidCardReceiptActivity} + */ + public Intent getIntentListPrepaidCardReceiptActivity(@NonNull final Context context, @NonNull final String token) { + Intent intent = new Intent(context, ListPrepaidCardReceiptActivity.class); + intent.putExtra(EXTRA_PREPAID_CARD_TOKEN, token); + return intent; } /** @@ -107,6 +119,4 @@ public Intent getIntentAddTransferMethodActivity(@NonNull final Context context, intent.putExtra(EXTRA_TRANSFER_METHOD_PROFILE_TYPE, profileType); return intent; } - - } From 0aea6312f6d600b872d2f3979c0981a547bb1523 Mon Sep 17 00:00:00 2001 From: Anna <48258136+azakrevska-epam@users.noreply.github.com> Date: Wed, 3 Jul 2019 03:39:36 +0300 Subject: [PATCH 021/177] HW-52989. Fixed restoring tree map (#46) --- .../android/ui/view/WidgetSelectionDialogFragment.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java index d3efca613..3a16ce03a 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/view/WidgetSelectionDialogFragment.java @@ -50,6 +50,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.TreeMap; public class WidgetSelectionDialogFragment extends DialogFragment implements ToolbarEventListener { @@ -105,7 +106,8 @@ public void onSaveInstanceState(@NonNull Bundle outState) { public void onViewStateRestored(@Nullable Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); if (savedInstanceState != null) { - mNameValueMap = (TreeMap) savedInstanceState.getSerializable(ARGUMENT_NAME_VALUE_MAP); + mNameValueMap = new TreeMap<>( + (Map) savedInstanceState.getSerializable(ARGUMENT_NAME_VALUE_MAP)); mSelectedName = savedInstanceState.getString(ARGUMENT_SELECTED_NAME); mSelectionLabel = savedInstanceState.getString(ARGUMENT_SELECTION_LABEL); mFieldName = savedInstanceState.getString(ARGUMENT_SELECTION_FIELD_NAME); @@ -154,7 +156,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c @Nullable Bundle savedInstanceState) { if (savedInstanceState != null) { // framework recreating previously destroyed instance - mNameValueMap = (TreeMap) savedInstanceState.getSerializable(ARGUMENT_NAME_VALUE_MAP); + mNameValueMap = new TreeMap<>( + (Map) savedInstanceState.getSerializable(ARGUMENT_NAME_VALUE_MAP)); mSelectedName = savedInstanceState.getString(ARGUMENT_SELECTED_NAME); mSelectionLabel = savedInstanceState.getString(ARGUMENT_SELECTION_LABEL); mFieldName = savedInstanceState.getString(ARGUMENT_SELECTION_FIELD_NAME); From 0807dffaf74812f14bbdcaccaa0b38b4cf8a3130 Mon Sep 17 00:00:00 2001 From: vshcherbyna-epam <48257687+vshcherbyna-epam@users.noreply.github.com> Date: Thu, 4 Jul 2019 19:24:51 +0300 Subject: [PATCH 022/177] HW-53770: List Receipts and Transaction Details UI Changes (#55) --- common/src/main/res/values/styles.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/common/src/main/res/values/styles.xml b/common/src/main/res/values/styles.xml index ba0f0ee2d..076d3a7d1 100644 --- a/common/src/main/res/values/styles.xml +++ b/common/src/main/res/values/styles.xml @@ -235,7 +235,6 @@ From 9602eb4e01e068cfbfe7b7ed5995d8c71a1f661b Mon Sep 17 00:00:00 2001 From: Shyang Koong Date: Thu, 4 Jul 2019 14:47:31 -0700 Subject: [PATCH 023/177] Task/hw 53039 receipt ppc ui tests (#54) --- .../receipt/ListPrepaidCardReceiptsTest.java | 380 +++++++++++++++++- .../ui/receipt/ListUserReceiptsTest.java | 10 +- .../PrepaidCardReceiptDataSource.java | 7 + .../PrepaidCardReceiptDataSourceTest.java | 10 +- .../prepaid_card_receipt_credit_response.json | 24 ++ .../prepaid_card_receipt_debit_response.json | 24 ++ ...> prepaid_card_receipt_list_response.json} | 15 +- ...id_card_receipt_unknown_type_response.json | 24 ++ 8 files changed, 479 insertions(+), 15 deletions(-) create mode 100644 receipt/src/test/resources/prepaid_card_receipt_credit_response.json create mode 100644 receipt/src/test/resources/prepaid_card_receipt_debit_response.json rename receipt/src/test/resources/{prepaid_card_receipt_list.json => prepaid_card_receipt_list_response.json} (83%) create mode 100644 receipt/src/test/resources/prepaid_card_receipt_unknown_type_response.json diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java index e9076ea1e..20802be1c 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java @@ -1,8 +1,19 @@ package com.hyperwallet.android.ui.receipt; +import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_SHOW_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_TIME; +import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_SHOW_YEAR; +import static android.text.format.DateUtils.formatDateTime; + import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; 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; @@ -13,6 +24,7 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT; import static java.net.HttpURLConnection.HTTP_OK; +import static com.hyperwallet.android.ui.receipt.util.EspressoUtils.atPosition; import static com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity.EXTRA_PREPAID_CARD_TOKEN; import android.content.Context; @@ -23,13 +35,17 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.espresso.IdlingRegistry; +import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.ui.common.util.DateUtils; import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.receipt.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.receipt.util.RecyclerViewCountAssertion; import com.hyperwallet.android.ui.receipt.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity; @@ -40,7 +56,11 @@ import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Date; import java.util.Locale; +import java.util.concurrent.TimeUnit; + +import okhttp3.mockwebserver.MockResponse; @RunWith(AndroidJUnit4.class) public class ListPrepaidCardReceiptsTest { @@ -78,18 +98,374 @@ public void unregisterIdlingResource() { } @Test - public void testListReceipt_userHasMultipleTransactions() { + public void testListPrepaidCardReceipt_userHasMultipleTransactions() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("prepaid_card_receipt_list_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.prepaid_card_sale))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("- 10.00"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("June 6, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(matches(atPosition(1, + hasDescendant(withText(R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(1, hasDescendant(withText(R.string.deposit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(1, hasDescendant(withText("+ 5.00"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(1, hasDescendant(withText("June 6, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(1, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(matches(atPosition(2, + hasDescendant(withText(R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(2, hasDescendant(withText(R.string.adjustment))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(2, hasDescendant(withText("- 8.90"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(2, hasDescendant(withText("June 1, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(2, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(3, hasDescendant(withText("March 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(3, + hasDescendant(withText(R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(3, hasDescendant(withText(R.string.adjustment))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(3, hasDescendant(withText("- 7.90"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(3, hasDescendant(withText("March 31, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(3, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(matches(atPosition(4, + hasDescendant(withText(R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(4, hasDescendant(withText(R.string.adjustment))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(4, hasDescendant(withText("+ 6.90"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(4, hasDescendant(withText("February 28, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(4, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(matches(atPosition(5, + hasDescendant(withText(R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(5, hasDescendant(withText(R.string.adjustment))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(5, hasDescendant(withText("+ 3.90"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(5, hasDescendant(withText("February 23, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(5, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(matches(atPosition(6, + hasDescendant(withText(R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(6, hasDescendant(withText(R.string.adjustment))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(6, hasDescendant(withText("+ 9.92"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(6, hasDescendant(withText("February 21, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(6, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(7)); + } + + @Test + public void testListPrepaidCardReceipt_userHasCreditTransaction() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("prepaid_card_receipt_credit_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.deposit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("+ 15.00"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("June 6, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("CAD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); + } + + @Test + public void testListPrepaidCardReceipt_userHasDebitTransaction() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("prepaid_card_receipt_debit_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.adjustment))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("- 8.90"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("June 1, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); + } + + @Test + public void testListPrepaidCardReceipt_userHasUnknownTransactionType() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("prepaid_card_receipt_unknown_type_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.credit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.unknown_type))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("+ 15.00"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("June 6, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("CAD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); + } + + @Test + public void testListPrepaidCardReceipt_userHasNoTransactions() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.toolbar)).check(matches(isDisplayed())); + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + //todo: check empty view when it will be ready + } + + @Test + public void testListPrepaidCardReceipt_checkDateTextOnLocaleChange() { mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager - .getResourceContent("prepaid_card_receipt_list.json")).mock(); + .getResourceContent("prepaid_card_receipt_debit_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + setLocale(Locale.GERMAN); // run test mActivityTestRule.launchActivity(null); + // assert + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("Juni 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.adjustment))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("- 8,90"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("1. Juni 2019"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); + } + + @Test + public void testListPrepaidCardReceipt_displaysNetworkErrorDialogOnConnectionTimeout() { + mMockWebServer.getServer().enqueue(new MockResponse().setResponseCode(HTTP_OK).setBody(sResourceManager + .getResourceContent("prepaid_card_receipt_debit_response.json")).throttleBody(512, 10, + TimeUnit.SECONDS)); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("prepaid_card_receipt_debit_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + mActivityTestRule.launchActivity(null); + + // assert error dialog information exist in portrait mode + onView(withText(R.string.error_dialog_connectivity_title)).check(matches(isDisplayed())); + onView(withText(R.string.io_exception)).check(matches(isDisplayed())); + onView(withId(android.R.id.button1)).check(matches(withText(R.string.try_again_button_label))); + onView(withId(android.R.id.button2)).check(matches(withText(R.string.cancel_button_label))); + + // retry button clicked + onView(withId(android.R.id.button1)).perform(click()); + onView(withText(R.string.error_dialog_connectivity_title)).check(doesNotExist()); // assert onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) .check(matches(withText(R.string.title_activity_receipt_list))); onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)) + .check(matches(atPosition(0, hasDescendant(withText("June 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, + hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.debit))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText(R.string.adjustment))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("- 8.90"))))); + onView(withId(R.id.list_receipts)).check( + matches(atPosition(0, hasDescendant(withText("June 1, 2019"))))); + onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText("USD"))))); + + onView(withId(R.id.list_receipts)).check(new RecyclerViewCountAssertion(1)); + } + + @Test + public void testListPrepaidCardReceipt_clickTransactionDisplaysDetails() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("prepaid_card_receipt_list_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); + + onView(withId(R.id.transaction_header_text)).check(matches(withText(R.string.transaction_header_text))); + onView(withId(R.id.transaction_type_icon)).check(matches(withText(R.string.debit))); + onView(withId(R.id.transaction_title)).check(matches(withText(R.string.prepaid_card_sale))); + onView(withId(R.id.transaction_amount)).check(matches(withText("- 10.00"))); + onView(withId(R.id.transaction_currency)).check(matches(withText("USD"))); + onView(withId(R.id.transaction_date)).check(matches(withText("June 6, 2019"))); + + onView(withId(R.id.receipt_details_header_label)).check(matches(withText(R.string.receipt_header_label))); + onView(withId(R.id.receipt_id_label)).check(matches(withText(R.string.journalId))); + onView(withId(R.id.receipt_id_value)).check(matches(withText("FISVL_5240220"))); + onView(withId(R.id.date_label)).check(matches(withText(R.string.createdOn))); + + Date date = DateUtils.fromDateTimeString("2019-06-06T22:48:41"); + String timezone = DateUtils.toDateFormat(date, "zzz"); + String text = mActivityTestRule.getActivity().getApplicationContext().getString( + R.string.concat_string_view_format, + formatDateTime(mActivityTestRule.getActivity().getApplicationContext(), date.getTime(), + FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_SHOW_YEAR + | FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_WEEKDAY), timezone); + onView(withId(R.id.date_value)).check(matches(withText(text))); + + onView(withId(R.id.client_id_label)).check(matches(withText(R.string.clientPaymentId))); + onView(withId(R.id.client_id_value)).check(matches(withText("AOxXefx9"))); + onView(withId(R.id.charity_label)).check(matches(withText(R.string.charityName))); + onView(withId(R.id.charity_value)).check(matches(withText("Sample Charity"))); + onView(withId(R.id.check_number_label)).check(matches(withText(R.string.checkNumber))); + onView(withId(R.id.check_number_value)).check(matches(withText("Sample Check Number"))); + onView(withId(R.id.website_label)).check(matches(withText(R.string.website))); + onView(withId(R.id.website_value)).check(matches(withText("https://api.sandbox.hyperwallet.com"))); + onView(withText("A Person")).check(doesNotExist()); + + onView(withId(R.id.receipt_notes_header_label)).check(matches(withText(R.string.notes))); + onView(withId(R.id.notes_value)).check( + matches(withText("Sample prepaid card payment for the period of June 15th, 2019 to July 23, 2019"))); + + onView(withId(R.id.details_header_text)).check(matches(withText(R.string.fee_details_header_text))); + onView(withId(R.id.details_amount_label)).check(matches(withText(R.string.details_amount_label))); + onView(withId(R.id.details_amount_value)).check(matches(withText("10.00 USD"))); + onView(withId(R.id.details_fee_label)).check(matches(withText(R.string.fee_label))); + onView(withId(R.id.details_fee_value)).check(matches(withText("3.00 USD"))); + onView(withId(R.id.details_transfer_amount_label)).check(matches(withText(R.string.transfer_amount_label))); + onView(withId(R.id.details_transfer_amount_value)).check(matches(withText("7.00 USD"))); + } + + @Test + public void testListPrepaidCardReceipt_clickTransactionDisplaysDetailsWithoutFees() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("prepaid_card_receipt_list_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + // run test + mActivityTestRule.launchActivity(null); + + // assert + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(R.string.title_activity_receipt_list))); + onView(withId(R.id.list_receipts)).check(matches(isDisplayed())); + + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.actionOnItemAtPosition(1, click())); + + onView(withId(R.id.transaction_header_text)).check(matches(withText(R.string.transaction_header_text))); + onView(withId(R.id.transaction_type_icon)).check(matches(withText(R.string.credit))); + onView(withId(R.id.transaction_title)).check(matches(withText(R.string.deposit))); + onView(withId(R.id.transaction_amount)).check(matches(withText("+ 5.00"))); + onView(withId(R.id.transaction_currency)).check(matches(withText("USD"))); + onView(withId(R.id.transaction_date)).check(matches(withText("June 6, 2019"))); + + onView(withId(R.id.receipt_details_header_label)).check(matches(withText(R.string.receipt_header_label))); + onView(withId(R.id.receipt_id_label)).check(matches(withText(R.string.journalId))); + onView(withId(R.id.receipt_id_value)).check(matches(withText("FISVL_5240221"))); + onView(withId(R.id.date_label)).check(matches(withText(R.string.createdOn))); + + Date date = DateUtils.fromDateTimeString("2019-06-06T22:48:51"); + String timezone = DateUtils.toDateFormat(date, "zzz"); + String text = mActivityTestRule.getActivity().getApplicationContext().getString( + R.string.concat_string_view_format, + formatDateTime(mActivityTestRule.getActivity().getApplicationContext(), date.getTime(), + FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_SHOW_YEAR + | FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_WEEKDAY), timezone); + onView(withId(R.id.date_value)).check(matches(withText(text))); + + onView(withId(R.id.client_id_label)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.client_id_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.charity_label)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.charity_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.check_number_label)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.check_number_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.website_label)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.website_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + + onView(withId(R.id.receipt_notes_information)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.receipt_notes_header_label)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); + onView(withId(R.id.notes_value)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))); } private void setLocale(Locale locale) { diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java index f510302c4..0bb97d2ff 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java @@ -110,7 +110,7 @@ public void testListReceipt_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check(matches(atPosition(0, hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.credit))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(0, hasDescendant(withText("Payment"))))); + matches(atPosition(0, hasDescendant(withText(R.string.payment))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(0, hasDescendant(withText("+ 20.00"))))); onView(withId(R.id.list_receipts)).check( @@ -120,7 +120,7 @@ public void testListReceipt_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check(matches(atPosition(1, hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.credit))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(1, hasDescendant(withText("Payment"))))); + matches(atPosition(1, hasDescendant(withText(R.string.payment))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(1, hasDescendant(withText("+ 25.00"))))); onView(withId(R.id.list_receipts)).check( @@ -130,7 +130,7 @@ public void testListReceipt_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check(matches(atPosition(2, hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.debit))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(2, hasDescendant(withText("Card Activation Fee"))))); + matches(atPosition(2, hasDescendant(withText(R.string.card_activation_fee))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(2, hasDescendant(withText("- 1.95"))))); onView(withId(R.id.list_receipts)).check( @@ -142,7 +142,7 @@ public void testListReceipt_userHasMultipleTransactions() { onView(withId(R.id.list_receipts)).check(matches(atPosition(3, hasDescendant(withText(com.hyperwallet.android.ui.receipt.R.string.debit))))); onView(withId(R.id.list_receipts)).check( - matches(atPosition(3, hasDescendant(withText("Card Load"))))); + matches(atPosition(3, hasDescendant(withText(R.string.transfer_to_prepaid_card))))); onView(withId(R.id.list_receipts)).check( matches(atPosition(3, hasDescendant(withText("- 18.05"))))); onView(withId(R.id.list_receipts)).check( @@ -417,7 +417,7 @@ public void testListReceipt_checkDateTextOnLocaleChange() { @Test public void testListReceipt_displaysNetworkErrorDialogOnConnectionTimeout() { mMockWebServer.getServer().enqueue(new MockResponse().setResponseCode(HTTP_OK).setBody(sResourceManager - .getResourceContent("receipt_debit_response.json")).throttleBody(512, 15, TimeUnit.SECONDS)); + .getResourceContent("receipt_debit_response.json")).throttleBody(512, 10, TimeUnit.SECONDS)); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("receipt_debit_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java index 352ae0913..7f4ca4ca4 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java @@ -31,6 +31,7 @@ import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.model.receipt.ReceiptQueryParam; +import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.common.viewmodel.Event; import com.hyperwallet.android.util.DateUtil; @@ -79,6 +80,7 @@ public void loadInitial(@NonNull final LoadInitialParams params, .createdAfter(mCalendarYearBeforeNow.getTime()) .sortByCreatedOnDesc().build(); + EspressoIdlingResource.increment(); getHyperwallet().listPrepaidCardReceipts(mToken, queryParam, new HyperwalletListener>() { @Override @@ -93,12 +95,14 @@ public void onSuccess(@Nullable HyperwalletPageList result) { // reset mLoadInitialCallback = null; mLoadInitialParams = null; + EspressoIdlingResource.decrement(); } @Override public void onFailure(HyperwalletException exception) { mIsFetchingData.postValue(Boolean.FALSE); mErrors.postValue(new Event<>(exception.getHyperwalletErrors())); + EspressoIdlingResource.decrement(); } @Override @@ -130,6 +134,7 @@ public void loadAfter(@NonNull final LoadParams params, @NonNull final Loa .limit(params.requestedLoadSize) .sortByCreatedOnDesc().build(); + EspressoIdlingResource.increment(); getHyperwallet().listPrepaidCardReceipts(mToken, queryParam, new HyperwalletListener>() { @Override @@ -144,12 +149,14 @@ public void onSuccess(@Nullable HyperwalletPageList result) { // reset mLoadAfterCallback = null; mLoadAfterParams = null; + EspressoIdlingResource.decrement(); } @Override public void onFailure(HyperwalletException exception) { mIsFetchingData.postValue(Boolean.FALSE); mErrors.postValue(new Event<>(exception.getHyperwalletErrors())); + EspressoIdlingResource.decrement(); } @Override diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java index f703e7810..acffd2881 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java @@ -14,8 +14,10 @@ import static org.mockito.Mockito.verify; import static com.hyperwallet.android.model.receipt.Receipt.Entries.CREDIT; +import static com.hyperwallet.android.model.receipt.Receipt.Entries.DEBIT; import static com.hyperwallet.android.model.receipt.Receipt.ReceiptTypes.ADJUSTMENT; import static com.hyperwallet.android.model.receipt.Receipt.ReceiptTypes.DEPOSIT; +import static com.hyperwallet.android.model.receipt.Receipt.ReceiptTypes.PREPAID_CARD_SALE; import androidx.paging.PageKeyedDataSource; @@ -88,7 +90,7 @@ public void setUp() { @Test public void testLoadInitial_returnsReceipts() throws Exception { - String json = mExternalResourceManager.getResourceContent("prepaid_card_receipt_list.json"); + String json = mExternalResourceManager.getResourceContent("prepaid_card_receipt_list_response.json"); JSONObject jsonObject = new JSONObject(json); final HyperwalletPageList response = new HyperwalletPageList<>(jsonObject, Receipt.class); @@ -118,9 +120,9 @@ public Object answer(InvocationOnMock invocation) { List receipts = mListArgumentCaptor.getValue(); assertThat(receipts, Matchers.hasSize(7)); assertThat(receipts.get(0).getJournalId(), is("FISVL_5240220")); - assertThat(receipts.get(0).getType(), is(DEPOSIT)); + assertThat(receipts.get(0).getType(), is(PREPAID_CARD_SALE)); assertThat(receipts.get(0).getCreatedOn(), is("2019-06-06T22:48:41")); - assertThat(receipts.get(0).getEntry(), is(CREDIT)); + assertThat(receipts.get(0).getEntry(), is(DEBIT)); assertThat(receipts.get(0).getDestinationToken(), is("trm-2e02da75-a36c-4723-b613-0b64e6f582d9")); assertThat(receipts.get(0).getAmount(), is("10.00")); assertThat(receipts.get(0).getCurrency(), is("USD")); @@ -245,7 +247,7 @@ public Object answer(InvocationOnMock invocation) { @Test public void testLoadAfter_returnsReceipts() throws Exception { - String json = mExternalResourceManager.getResourceContent("prepaid_card_receipt_list.json"); + String json = mExternalResourceManager.getResourceContent("prepaid_card_receipt_list_response.json"); JSONObject jsonObject = new JSONObject(json); final HyperwalletPageList response = new HyperwalletPageList<>(jsonObject, Receipt.class); diff --git a/receipt/src/test/resources/prepaid_card_receipt_credit_response.json b/receipt/src/test/resources/prepaid_card_receipt_credit_response.json new file mode 100644 index 000000000..152d482ba --- /dev/null +++ b/receipt/src/test/resources/prepaid_card_receipt_credit_response.json @@ -0,0 +1,24 @@ +{ + "data": [ + { + "journalId": "FISVL_5240220", + "type": "DEPOSIT", + "createdOn": "2019-06-06T22:48:41", + "entry": "CREDIT", + "destinationToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "15.00", + "currency": "CAD", + "details": { + "cardNumber": "************0673" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-e17ae43b-284d-4198-9585-f417943c624f/prepaid-cards/trm-2e02da75-a36c-4723-b613-0b64e6f582d9/receipts" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/prepaid_card_receipt_debit_response.json b/receipt/src/test/resources/prepaid_card_receipt_debit_response.json new file mode 100644 index 000000000..d26f5276c --- /dev/null +++ b/receipt/src/test/resources/prepaid_card_receipt_debit_response.json @@ -0,0 +1,24 @@ +{ + "data": [ + { + "journalId": "FISA_5240222", + "type": "ADJUSTMENT", + "createdOn": "2019-06-01T22:49:17", + "entry": "DEBIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "8.90", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-e17ae43b-284d-4198-9585-f417943c624f/prepaid-cards/trm-2e02da75-a36c-4723-b613-0b64e6f582d9/receipts" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/prepaid_card_receipt_list.json b/receipt/src/test/resources/prepaid_card_receipt_list_response.json similarity index 83% rename from receipt/src/test/resources/prepaid_card_receipt_list.json rename to receipt/src/test/resources/prepaid_card_receipt_list_response.json index 95715bb7a..e6539804c 100644 --- a/receipt/src/test/resources/prepaid_card_receipt_list.json +++ b/receipt/src/test/resources/prepaid_card_receipt_list_response.json @@ -2,14 +2,21 @@ "data": [ { "journalId": "FISVL_5240220", - "type": "DEPOSIT", + "type": "PREPAID_CARD_SALE", "createdOn": "2019-06-06T22:48:41", - "entry": "CREDIT", + "entry": "DEBIT", "destinationToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", "amount": "10.00", + "fee": "3.00", "currency": "USD", "details": { - "cardNumber": "************0673" + "cardNumber": "************0673", + "clientPaymentId": "AOxXefx9", + "payeeName": "A Person", + "website": "https://api.sandbox.hyperwallet.com", + "notes": "Sample prepaid card payment for the period of June 15th, 2019 to July 23, 2019", + "charityName": "Sample Charity", + "checkNumber": "Sample Check Number" } }, { @@ -27,7 +34,7 @@ { "journalId": "FISA_5240222", "type": "ADJUSTMENT", - "createdOn": "2019-06-06T22:49:17", + "createdOn": "2019-06-01T22:49:17", "entry": "DEBIT", "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", "amount": "8.90", diff --git a/receipt/src/test/resources/prepaid_card_receipt_unknown_type_response.json b/receipt/src/test/resources/prepaid_card_receipt_unknown_type_response.json new file mode 100644 index 000000000..e2d1f2e8c --- /dev/null +++ b/receipt/src/test/resources/prepaid_card_receipt_unknown_type_response.json @@ -0,0 +1,24 @@ +{ + "data": [ + { + "journalId": "FISVL_5240220", + "type": "CARD_WAIVER_FEE", + "createdOn": "2019-06-06T22:48:41", + "entry": "CREDIT", + "destinationToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "15.00", + "currency": "CAD", + "details": { + "cardNumber": "************0673" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-e17ae43b-284d-4198-9585-f417943c624f/prepaid-cards/trm-2e02da75-a36c-4723-b613-0b64e6f582d9/receipts" + } + ] +} \ No newline at end of file From 3aa88299062c41e6b3baca8440735b27a80541b8 Mon Sep 17 00:00:00 2001 From: Anna <48258136+azakrevska-epam@users.noreply.github.com> Date: Sat, 6 Jul 2019 02:00:04 +0300 Subject: [PATCH 024/177] HW-53657. UI processing time (#52) --- common/config/jacoco-settings.gradle | 12 +- receipt/config/jacoco-settings.gradle | 15 +- .../PrepaidCardReceiptDataSource.java | 6 +- .../PrepaidCardReceiptDataSourceTest.java | 8 ++ .../PrepaidCardReceiptRepositoryImplTest.java | 69 +++++++++ .../UserReceiptRepositoryImplTest.java | 69 +++++++++ ui/config/jacoco-settings.gradle | 8 +- .../ui/transfermethod/BankAccountTest.java | 12 +- .../ui/transfermethod/BankCardTest.java | 11 +- .../android/ui/transfermethod/PayPalTest.java | 11 +- .../SelectTransferMethodTest.java | 2 + ...TransferMethodConfigurationRepository.java | 3 +- ...sferMethodConfigurationRepositoryImpl.java | 23 +-- .../AddTransferMethodContract.java | 5 +- .../AddTransferMethodFragment.java | 7 +- .../AddTransferMethodPresenter.java | 6 +- .../SelectTransferMethodFragment.java | 5 +- .../TransferMethodSelectionItem.java | 9 +- ...MethodConfigurationRepositoryImplTest.java | 10 +- .../AddTransferMethodPresenterTest.java | 6 +- ...sful_tmc_fields_bank_account_response.json | 14 +- ...cessful_tmc_fields_bank_card_response.json | 10 ++ ...successful_tmc_fields_paypal_response.json | 10 ++ ...uccessful_tmc_keys_empty_fee_response.json | 11 +- .../successful_tmc_keys_response.json | 132 ++++++++++++++++-- 25 files changed, 381 insertions(+), 93 deletions(-) create mode 100644 receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java create mode 100644 receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java diff --git a/common/config/jacoco-settings.gradle b/common/config/jacoco-settings.gradle index 7ce61b7aa..0fe7bbd10 100644 --- a/common/config/jacoco-settings.gradle +++ b/common/config/jacoco-settings.gradle @@ -20,10 +20,16 @@ android { } } -def fileFilter = ['**/BuildConfig.*'] +def fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.*', + '**/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.*', + '**/com/hyperwallet/android/ui/common/view/OneClickListener.*', + '**/com/hyperwallet/android/ui/common/util/EspressoIdlingResource.*', + '**/com/hyperwallet/android/ui/common/viewmodel/Event.*' +] def debugClassPaths = [ - '**/intermediates/javac/dev/*/classes/**' + '**/intermediates/javac/debug/*/classes/**' ] final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] @@ -48,7 +54,7 @@ task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { additionalSourceDirs = files(coverageSourceDirs) sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDevUnitTest.exec") + executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") } task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { diff --git a/receipt/config/jacoco-settings.gradle b/receipt/config/jacoco-settings.gradle index 7ce61b7aa..e0bb22486 100644 --- a/receipt/config/jacoco-settings.gradle +++ b/receipt/config/jacoco-settings.gradle @@ -20,10 +20,14 @@ android { } } -def fileFilter = ['**/BuildConfig.*'] +def fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/receipt/view/*.*', + '**/com/hyperwallet/android/ui/receipt/viewmodel/*.*', + '**/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryImpl.*' +] def debugClassPaths = [ - '**/intermediates/javac/dev/*/classes/**' + '**/intermediates/javac/debug/*/classes/**' ] final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] @@ -32,11 +36,10 @@ task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { group = 'Reporting' description = 'Generate Jacoco coverage reports.' - reports { html { enabled = true - destination file("$buildDir/reports/jacoco") + destination file("$project.buildDir/reports/jacoco") } } @@ -48,7 +51,7 @@ task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { additionalSourceDirs = files(coverageSourceDirs) sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDevUnitTest.exec") + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") } task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { @@ -61,7 +64,7 @@ task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: ) additionalSourceDirs = files(coverageSourceDirs) sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") violationRules { setFailOnViolation(true) diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java index 7f4ca4ca4..39135cf44 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java +++ b/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java @@ -20,6 +20,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.paging.PageKeyedDataSource; @@ -194,8 +195,9 @@ Hyperwallet getHyperwallet() { return Hyperwallet.getDefault(); } - private Date getNextDate(@Nullable final HyperwalletPageList result) { - if (result != null && result.getDataList() != null && !result.getDataList().isEmpty()) { + @VisibleForTesting + Date getNextDate(@NonNull final HyperwalletPageList result) { + if (result.getDataList() != null && !result.getDataList().isEmpty()) { // get last receipt date return DateUtil.fromDateTimeString( result.getDataList().get(result.getDataList().size() - 1).getCreatedOn()); diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java index acffd2881..e9cf99b89 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java @@ -33,6 +33,7 @@ import com.hyperwallet.android.util.DateUtil; import org.hamcrest.Matchers; +import org.json.JSONException; import org.json.JSONObject; import org.junit.Before; import org.junit.Rule; @@ -395,4 +396,11 @@ public Object answer(InvocationOnMock invocation) { ArgumentMatchers.>any(), ArgumentMatchers.>any()); } + + @Test + public void testGetNextDate_verifyDefaultValue() { + Date date = mPrepaidCardReceiptDataSource.getNextDate(new HyperwalletPageList(null)); + assertThat(date, is(notNullValue())); + } + } diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java new file mode 100644 index 000000000..247031513 --- /dev/null +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java @@ -0,0 +1,69 @@ +package com.hyperwallet.android.ui.receipt.repository; + + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertTrue; + +import androidx.lifecycle.LiveData; +import androidx.paging.PagedList; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.viewmodel.Event; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class PrepaidCardReceiptRepositoryImplTest { + + + private PrepaidCardReceiptRepository mPrepaidCardReceiptRepository = new PrepaidCardReceiptRepositoryImpl( + "trm-aa308d58-75b4-432b-dec1-eb6b9e341111"); + + @Test + public void testLoadPrepaidCardReceipts_returnsLiveData() { + LiveData> result = mPrepaidCardReceiptRepository.loadPrepaidCardReceipts(); + assertThat(result, is(notNullValue())); + LiveData> result2 = mPrepaidCardReceiptRepository.loadPrepaidCardReceipts(); + assertTrue(result == result2); + } + + @Test + public void testLoadPrepaidCardReceipts_liveDataSingleInstantiation() { + LiveData> result = mPrepaidCardReceiptRepository.loadPrepaidCardReceipts(); + LiveData> result2 = mPrepaidCardReceiptRepository.loadPrepaidCardReceipts(); + assertTrue(result == result2); + } + + @Test + public void testIsLoading_returnsLiveData() { + LiveData result = mPrepaidCardReceiptRepository.isLoading(); + assertThat(result, is(notNullValue())); + } + + @Test + public void testIsLoading_liveDataSingleInstantiation() { + LiveData result = mPrepaidCardReceiptRepository.isLoading(); + LiveData result2 = mPrepaidCardReceiptRepository.isLoading(); + assertTrue(result == result2); + + } + + @Test + public void testGetErrors_returnsLiveData() { + LiveData> result = mPrepaidCardReceiptRepository.getErrors(); + assertThat(result, is(notNullValue())); + } + + @Test + public void testGetErrors_liveDataSingleInstantiation() { + LiveData> result = mPrepaidCardReceiptRepository.getErrors(); + LiveData> result2 = mPrepaidCardReceiptRepository.getErrors(); + assertTrue(result == result2); + } + +} \ No newline at end of file diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java new file mode 100644 index 000000000..5b3005bda --- /dev/null +++ b/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java @@ -0,0 +1,69 @@ +package com.hyperwallet.android.ui.receipt.repository; + + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertTrue; + +import androidx.lifecycle.LiveData; +import androidx.paging.PagedList; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.viewmodel.Event; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class UserReceiptRepositoryImplTest { + + + private UserReceiptRepository mUserReceiptRepository = new UserReceiptRepositoryImpl(); + + @Test + public void testLoadUserReceipts_returnsLiveData() { + LiveData> result = mUserReceiptRepository.loadUserReceipts(); + assertThat(result, is(notNullValue())); + LiveData> result2 = mUserReceiptRepository.loadUserReceipts(); + assertTrue(result == result2); + } + + @Test + public void testLoadUserReceipts_liveDataSingleInstantiation() { + LiveData> result = mUserReceiptRepository.loadUserReceipts(); + LiveData> result2 = mUserReceiptRepository.loadUserReceipts(); + assertTrue(result == result2); + } + + @Test + public void testIsLoading_returnsLiveData() { + LiveData result = mUserReceiptRepository.isLoading(); + assertThat(result, is(notNullValue())); + } + + @Test + public void testIsLoading_liveDataSingleInstantiation() { + LiveData result = mUserReceiptRepository.isLoading(); + LiveData result2 = mUserReceiptRepository.isLoading(); + assertTrue(result == result2); + + } + + @Test + public void testGetErrors_returnsLiveData() { + LiveData> result = mUserReceiptRepository.getErrors(); + assertThat(result, is(notNullValue())); + } + + @Test + public void testGetErrors_liveDataSingleInstantiation() { + LiveData> result = mUserReceiptRepository.getErrors(); + LiveData> result2 = mUserReceiptRepository.getErrors(); + assertTrue(result == result2); + } + + +} \ No newline at end of file diff --git a/ui/config/jacoco-settings.gradle b/ui/config/jacoco-settings.gradle index c810d1d89..9cb13e331 100644 --- a/ui/config/jacoco-settings.gradle +++ b/ui/config/jacoco-settings.gradle @@ -27,10 +27,10 @@ def fileFilter = ['**/BuildConfig.*', '**/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.*', '**/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.*', '**/com/hyperwallet/android/ui/view/HorizontalDividerItemDecorator.*', - '**/com/hyperwallet/android/ui/view/widget/*'] - + '**/com/hyperwallet/android/ui/view/widget/*' +] def debugClassPaths = [ - '**/intermediates/javac/dev/*/classes/**' + '**/intermediates/javac/debug/*/classes/**' ] final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] @@ -55,7 +55,7 @@ task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { additionalSourceDirs = files(coverageSourceDirs) sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDevUnitTest.exec") + executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") } task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java index 45d92c6a7..4ac416f78 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java @@ -196,12 +196,12 @@ public void testAddTransferMethod_displaysFeeElementsOnTmcResponse() { matches(withText(R.string.add_transfer_method_fee_label))); onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("USD 2.00"))); - //TODO: Uncomment when processing time node is implemented -// onView(withId(R.id.add_transfer_method_processing_label)).check( -// matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); -// onView(withId(R.id.add_transfer_method_processing_label)).check( -// matches(withText(R.string.add_transfer_method_processing_time_label))); -// onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("1 - 2 Business Days"))); + onView(withId(R.id.add_transfer_method_processing_label)) + .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); + onView(withId(R.id.add_transfer_method_processing_label)) + .check(matches(withText(R.string.add_transfer_method_processing_time_label))); + onView(withId(R.id.add_transfer_method_processing_time_value)) + .check(matches(withText("1-2 Business days"))); } @Test diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java index 8f98ffabf..44ea7393f 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java @@ -155,12 +155,11 @@ public void testAddTransferMethod_displaysFeeElementsOnTmcResponse() { matches(withText(R.string.add_transfer_method_fee_label))); onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("USD 1.75"))); - //TODO: Uncomment when processing time node is implemented -// onView(withId(R.id.add_transfer_method_processing_label)).check( -// matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); -// onView(withId(R.id.add_transfer_method_processing_label)).check( -// matches(withText(R.string.add_transfer_method_processing_time_label))); -// onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("1 - 2 Business Days"))); + onView(withId(R.id.add_transfer_method_processing_label)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); + onView(withId(R.id.add_transfer_method_processing_label)).check( + matches(withText(R.string.add_transfer_method_processing_time_label))); + onView(withId(R.id.add_transfer_method_processing_time_value)).check(matches(withText("IMMEDIATE"))); } @Test diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java index 1bef2a80a..ebf34101b 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java @@ -150,12 +150,11 @@ public void testAddTransferMethod_displaysFeeElementsOnTmcResponse() { matches(withText(R.string.add_transfer_method_fee_label))); onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("USD 0.25"))); - //TODO: Uncomment when processing time node is implemented -// onView(withId(R.id.add_transfer_method_processing_label)).check( -// matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); -// onView(withId(R.id.add_transfer_method_processing_label)).check( -// matches(withText(R.string.add_transfer_method_processing_time_label))); -// onView(withId(R.id.add_transfer_method_fee_value)).check(matches(withText("IMMEDIATE"))); + onView(withId(R.id.add_transfer_method_processing_label)).check( + matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))); + onView(withId(R.id.add_transfer_method_processing_label)).check( + matches(withText(R.string.add_transfer_method_processing_time_label))); + onView(withId(R.id.add_transfer_method_processing_time_value)).check(matches(withText("IMMEDIATE"))); } diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java index ad44411c8..c67aea94c 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java @@ -225,6 +225,8 @@ public void testSelectTransferMethod_verifyTransferMethodsList() { matches(atPosition(1, hasDescendant(withText(R.string.bank_card))))); onView(withId(R.id.select_transfer_method_types_list)).check( matches(atPosition(1, hasDescendant(withText("Transaction Fee: USD 1.75"))))); + onView(withId(R.id.select_transfer_method_types_list)).check( + matches(atPosition(1, hasDescendant(withText("Processing Time: IMMEDIATE"))))); onView(withId(R.id.select_transfer_method_types_list)).check( matches(atPosition(2, hasDescendant(withText(R.string.wire_account_font_icon))))); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java index 165e21565..08c9694e3 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java @@ -54,8 +54,7 @@ interface LoadKeysCallback { interface LoadFieldsCallback { - void onFieldsLoaded(@Nullable final HyperwalletTransferMethodConfigurationField field, - @Nullable final String processingTime); + void onFieldsLoaded(@Nullable final HyperwalletTransferMethodConfigurationField field); void onError(@NonNull final HyperwalletErrors errors); } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java index a058b61d3..b8384793f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java @@ -37,7 +37,6 @@ 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.keyed.HyperwalletTransferMethodType; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationFieldQuery; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationKeysQuery; import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; @@ -45,7 +44,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.Set; public class TransferMethodConfigurationRepositoryImpl implements TransferMethodConfigurationRepository { private final Handler mHandler; @@ -117,8 +115,7 @@ void getTransferMethodConfigurationFieldResult(@NonNull final String country, public void onSuccess(HyperwalletTransferMethodConfigurationField result) { FieldMapKey fieldMapKey = new FieldMapKey(country, currency, transferMethodType); mFieldMap.put(fieldMapKey, result); - loadFieldsCallback.onFieldsLoaded(result, - getProcessingTime(country, currency, transferMethodType)); + loadFieldsCallback.onFieldsLoaded(result); EspressoIdlingResource.decrement(); } @@ -159,8 +156,7 @@ public synchronized void getFields(@NonNull final String country, @NonNull final getTransferMethodConfigurationFieldResult(country, currency, transferMethodType, transferMethodProfileType, loadFieldsCallback); } else { - loadFieldsCallback.onFieldsLoaded(transferMethodConfigurationField, - getProcessingTime(country, currency, transferMethodType)); + loadFieldsCallback.onFieldsLoaded(transferMethodConfigurationField); } } @@ -174,21 +170,6 @@ public void refreshFields() { mFieldMap.clear(); } - //TODO this method is just temporary, placed to get the processing time - //Next iteration from API will have ProcessingTime as a separate node - @Nullable - private String getProcessingTime(String country, String currency, String transferMethodType) { - if (mTransferMethodConfigurationKey != null) { - Set transferMethodTypes = mTransferMethodConfigurationKey - .getTransferMethodType(country, currency); - for (HyperwalletTransferMethodType type : transferMethodTypes) { - if (type.getName().equals(transferMethodType)) { - return type.getProcessingTime(); - } - } - } - return null; - } } class FieldMapKey { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java index 2d0aec1f4..959e0a03e 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java @@ -17,9 +17,11 @@ package com.hyperwallet.android.ui.transfermethod; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.graphql.HyperwalletFee; +import com.hyperwallet.android.model.graphql.ProcessingTime; import com.hyperwallet.android.model.graphql.field.HyperwalletFieldGroup; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; @@ -40,7 +42,8 @@ interface View { void showTransferMethodFields(@NonNull final List fields); - void showTransactionInformation(List fees, String processingTime); + void showTransactionInformation(@NonNull final List fees, + @Nullable final ProcessingTime processingTime); void showCreateButtonProgressBar(); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java index e34075468..447624e31 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java @@ -48,6 +48,7 @@ import com.hyperwallet.android.exception.HyperwalletException; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.graphql.HyperwalletFee; +import com.hyperwallet.android.model.graphql.ProcessingTime; import com.hyperwallet.android.model.graphql.field.HyperwalletField; import com.hyperwallet.android.model.graphql.field.HyperwalletFieldGroup; import com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount; @@ -356,7 +357,7 @@ private String getSectionHeaderText(@NonNull final HyperwalletFieldGroup group, @Override public void showTransactionInformation(@NonNull final List fees, - @Nullable final String processingTime) { + @Nullable final ProcessingTime processingTime) { View header = getView().findViewById(R.id.add_transfer_method_static_container_header); View container = getView().findViewById(R.id.add_transfer_method_static_container); View feeLabel = getView().findViewById(R.id.add_transfer_method_fee_label); @@ -376,8 +377,8 @@ public void showTransactionInformation(@NonNull final List fees, feeValue.setVisibility(View.GONE); } - if (!TextUtils.isEmpty(processingTime)) { - processingTimeValue.setText(processingTime); + if (processingTime != null && !TextUtils.isEmpty(processingTime.getValue())) { + processingTimeValue.setText(processingTime.getValue()); processingTimeLabel.setVisibility(View.VISIBLE); processingTimeValue.setVisibility(View.VISIBLE); if (feeValue.getVisibility() == View.GONE) { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java index a2b23bdee..d0fd40750 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java @@ -17,7 +17,6 @@ package com.hyperwallet.android.ui.transfermethod; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; @@ -85,8 +84,7 @@ public void loadTransferMethodConfigurationFields(final boolean forceUpdate, @No country, currency, transferMethodType, transferMethodProfileType, new TransferMethodConfigurationRepository.LoadFieldsCallback() { @Override - public void onFieldsLoaded(HyperwalletTransferMethodConfigurationField field, - @Nullable final String processingTime) { + public void onFieldsLoaded(HyperwalletTransferMethodConfigurationField field) { if (!mView.isActive()) { return; } @@ -94,7 +92,7 @@ public void onFieldsLoaded(HyperwalletTransferMethodConfigurationField field, mView.hideProgressBar(); mView.showTransferMethodFields(field.getFields().getFieldGroups()); // there can be multiple fees when we have flat fee + percentage fees - mView.showTransactionInformation(field.getFees(), processingTime); + mView.showTransactionInformation(field.getFees(), field.getProcessingTime()); } @Override diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java index 5f284a8d4..b18a9cb93 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java @@ -469,10 +469,11 @@ void bind(TransferMethodSelectionItem selectionItem) { mDescriptionFees.setVisibility(View.GONE); } - if (!TextUtils.isEmpty(selectionItem.getProcessingTime())) { + if (selectionItem.getProcessingTime() != null && !TextUtils.isEmpty( + selectionItem.getProcessingTime().getValue())) { mDescriptionProcessingTime.setText(mDescriptionProcessingTime.getContext() .getString(R.string.select_transfer_method_item_processing_time_information, - selectionItem.getProcessingTime())); + selectionItem.getProcessingTime().getValue())); mDescriptionProcessingTime.setVisibility(View.VISIBLE); } else { mDescriptionProcessingTime.setVisibility(View.INVISIBLE); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java index e116f9368..eb5dbabab 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.java @@ -17,8 +17,10 @@ package com.hyperwallet.android.ui.transfermethod; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.hyperwallet.android.model.graphql.HyperwalletFee; +import com.hyperwallet.android.model.graphql.ProcessingTime; import java.util.ArrayList; import java.util.List; @@ -30,14 +32,14 @@ public class TransferMethodSelectionItem { private final String mCountry; private final String mCurrency; private final List mFees; - private final String mProcessingTime; + private final ProcessingTime mProcessingTime; private final String mProfileType; private final String mTransferMethodType; private final String mTransferMethodName; public TransferMethodSelectionItem(@NonNull final String country, @NonNull final String currency, @NonNull final String profileType, @NonNull final String transferMethodType, - @NonNull final String transferMethodName, @NonNull final String processingTime, + @NonNull final String transferMethodName, @Nullable final ProcessingTime processingTime, @NonNull final Set fees) { mCountry = country; mCurrency = currency; @@ -68,7 +70,8 @@ public String getTransferMethodType() { return mTransferMethodType; } - public String getProcessingTime() { + @Nullable + public ProcessingTime getProcessingTime() { return mProcessingTime; } diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java index aec2aad6d..7bcc36886 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java @@ -6,7 +6,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -79,8 +78,6 @@ public class TransferMethodConfigurationRepositoryImplTest { private ArgumentCaptor fieldResultArgumentCaptor; @Captor private ArgumentCaptor mErrorsArgumentCaptor; - @Captor - private ArgumentCaptor mStringArgumentCaptor; @Mock private Hyperwallet mHyperwallet; @Mock @@ -181,7 +178,7 @@ public Object answer(InvocationOnMock invocation) { mTransferMethodConfigurationRepositoryImplMock.getFields(COUNTRY, CURRENCY, TRANSFER_METHOD_TYPE, INDIVIDUAL, loadFieldsCallback); - verify(loadFieldsCallback).onFieldsLoaded(fieldResultArgumentCaptor.capture(), mStringArgumentCaptor.capture()); + verify(loadFieldsCallback).onFieldsLoaded(fieldResultArgumentCaptor.capture()); verify(loadFieldsCallback, never()).onError(any(HyperwalletErrors.class)); HyperwalletTransferMethodConfigurationField transferMethodConfigurationFieldResult = @@ -219,8 +216,7 @@ public Object answer(InvocationOnMock invocation) { mTransferMethodConfigurationRepositoryImplMock.getFields(COUNTRY, CURRENCY, TRANSFER_METHOD_TYPE, INDIVIDUAL, loadFieldsCallback); - verify(loadFieldsCallback, never()).onFieldsLoaded( - any(HyperwalletTransferMethodConfigurationField.class), anyString()); + verify(loadFieldsCallback, never()).onFieldsLoaded(any(HyperwalletTransferMethodConfigurationField.class)); verify(loadFieldsCallback).onError(mErrorsArgumentCaptor.capture()); HyperwalletErrors hyperwalletErrors = mErrorsArgumentCaptor.getValue(); @@ -270,7 +266,7 @@ public void testGetFields_callsListenerWithFieldResultFromCacheWhenNotNull() thr any(String.class), any(String.class), any(TransferMethodConfigurationRepository.LoadFieldsCallback.class)); - verify(loadFieldsCallback).onFieldsLoaded(fieldResultArgumentCaptor.capture(), mStringArgumentCaptor.capture()); + verify(loadFieldsCallback).onFieldsLoaded(fieldResultArgumentCaptor.capture()); verify(loadFieldsCallback, never()).onError(any(HyperwalletErrors.class)); } diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java index 623caad7b..399c188bb 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java @@ -19,6 +19,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.graphql.HyperwalletFee; import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; +import com.hyperwallet.android.model.graphql.ProcessingTime; import com.hyperwallet.android.model.graphql.field.HyperwalletFieldGroup; import com.hyperwallet.android.model.graphql.field.HyperwalletTransferMethodConfiguration; import com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount; @@ -150,7 +151,7 @@ public void testLoadTransferMethodConfigurationFields_loadsTransferMethodFieldsI public Object answer(InvocationOnMock invocation) { TransferMethodConfigurationRepository.LoadFieldsCallback callback = (TransferMethodConfigurationRepository.LoadFieldsCallback) invocation.getArguments()[4]; - callback.onFieldsLoaded(result, ""); + callback.onFieldsLoaded(result); return callback; } }).when(tmcRepository).getFields(anyString(), anyString(), anyString(), anyString(), @@ -219,7 +220,8 @@ public void testLoadTransferMethodConfigurationFields_loadsTransferMethodFieldsI any(TransferMethodConfigurationRepository.LoadFieldsCallback.class)); verify(view, never()).hideProgressBar(); verify(view, never()).showTransferMethodFields(ArgumentMatchers.anyList()); - verify(view, never()).showTransactionInformation(ArgumentMatchers.anyList(), anyString()); + verify(view, never()).showTransactionInformation(ArgumentMatchers.anyList(), + any(ProcessingTime.class)); } @Test diff --git a/ui/src/test/resources/successful_tmc_fields_bank_account_response.json b/ui/src/test/resources/successful_tmc_fields_bank_account_response.json index affe5272e..238492d0b 100644 --- a/ui/src/test/resources/successful_tmc_fields_bank_account_response.json +++ b/ui/src/test/resources/successful_tmc_fields_bank_account_response.json @@ -53,11 +53,11 @@ "fieldSelectionOptions": [ { "label": "Checking", - "value": "CHECKING" + "value": "Checking" }, { "label": "Savings", - "value": "SAVINGS" + "value": "Savings" } ], "label": "Account Type", @@ -1235,6 +1235,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "country": "US", + "currency": "USD", + "transferMethodType": "BANK_ACCOUNT", + "value": "1-2 Business days" + } + ] } } } \ No newline at end of file diff --git a/ui/src/test/resources/successful_tmc_fields_bank_card_response.json b/ui/src/test/resources/successful_tmc_fields_bank_card_response.json index dc91b7d32..4f64d2294 100644 --- a/ui/src/test/resources/successful_tmc_fields_bank_card_response.json +++ b/ui/src/test/resources/successful_tmc_fields_bank_card_response.json @@ -1119,6 +1119,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "country": "US", + "currency": "USD", + "transferMethodType": "BANK_CARD", + "value": "IMMEDIATE" + } + ] } } } \ No newline at end of file diff --git a/ui/src/test/resources/successful_tmc_fields_paypal_response.json b/ui/src/test/resources/successful_tmc_fields_paypal_response.json index 96d40fdbc..adf27664c 100644 --- a/ui/src/test/resources/successful_tmc_fields_paypal_response.json +++ b/ui/src/test/resources/successful_tmc_fields_paypal_response.json @@ -1188,6 +1188,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "country": "US", + "currency": "USD", + "transferMethodType": "BANK_CARD", + "value": "IMMEDIATE" + } + ] } } } \ No newline at end of file diff --git a/ui/src/test/resources/successful_tmc_keys_empty_fee_response.json b/ui/src/test/resources/successful_tmc_keys_empty_fee_response.json index 435561fa5..d0c8ebbed 100644 --- a/ui/src/test/resources/successful_tmc_keys_empty_fee_response.json +++ b/ui/src/test/resources/successful_tmc_keys_empty_fee_response.json @@ -15,7 +15,16 @@ { "code": "BANK_ACCOUNT", "name": "Bank Account", - "processingTime": "1-2 Business days" + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "US", + "currency": "USD", + "transferMethodType": "BANK_ACCOUNT" + } + ] + } } ] } diff --git a/ui/src/test/resources/successful_tmc_keys_response.json b/ui/src/test/resources/successful_tmc_keys_response.json index f4e9eb831..64d4c6d00 100644 --- a/ui/src/test/resources/successful_tmc_keys_response.json +++ b/ui/src/test/resources/successful_tmc_keys_response.json @@ -15,7 +15,6 @@ { "code": "BANK_ACCOUNT", "name": "Bank Account", - "processingTime": "1-2 Business days", "fees": { "nodes": [ { @@ -26,12 +25,21 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "CA", + "currency": "CAD", + "transferMethodType": "BANK_ACCOUNT" + } + ] } }, { "code": "PAYPAL_ACCOUNT", "name": "PayPal Account", - "processingTime": "IMMEDIATE", "fees": { "nodes": [ { @@ -42,6 +50,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "IMMEDIATE", + "country": "CA", + "currency": "CAD", + "transferMethodType": "PAYPAL_ACCOUNT" + } + ] } } ] @@ -55,7 +73,6 @@ { "code": "BANK_ACCOUNT", "name": "Bank Account", - "processingTime": "1-2 Business days", "fees": { "nodes": [ { @@ -66,6 +83,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "CA", + "currency": "USD", + "transferMethodType": "BANK_ACCOUNT" + } + ] } } ] @@ -87,7 +114,6 @@ { "code": "BANK_ACCOUNT", "name": "Bank Account", - "processingTime": "2-3 Business days", "fees": { "nodes": [ { @@ -98,6 +124,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "2-3 Business days", + "country": "HR", + "currency": "EUR", + "transferMethodType": "BANK_ACCOUNT" + } + ] } } ] @@ -111,7 +147,6 @@ { "code": "BANK_ACCOUNT", "name": "Bank Account", - "processingTime": "1-2 Business days", "fees": { "nodes": [ { @@ -122,6 +157,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "HR", + "currency": "HRK", + "transferMethodType": "BANK_ACCOUNT" + } + ] } } ] @@ -143,7 +188,6 @@ { "code": "BANK_ACCOUNT", "name": "Bank Account", - "processingTime": "1-2 Business days", "fees": { "nodes": [ { @@ -154,6 +198,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "MX", + "currency": "MXN", + "transferMethodType": "BANK_ACCOUNT" + } + ] } } ] @@ -175,7 +229,6 @@ { "code": "BANK_ACCOUNT", "name": "Bank Account", - "processingTime": "2-4 Business days", "fees": { "nodes": [ { @@ -186,6 +239,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "2-4 Business days", + "country": "GB", + "currency": "EUR", + "transferMethodType": "BANK_ACCOUNT" + } + ] } } ] @@ -199,7 +262,6 @@ { "code": "BANK_ACCOUNT", "name": "Bank Account", - "processingTime": "1-2 Business days", "fees": { "nodes": [ { @@ -210,6 +272,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "GB", + "currency": "GBP", + "transferMethodType": "BANK_ACCOUNT" + } + ] } } ] @@ -231,7 +303,6 @@ { "code": "BANK_ACCOUNT", "name": "Bank Account", - "processingTime": "1-2 Business days", "fees": { "nodes": [ { @@ -242,6 +313,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "US", + "currency": "USD", + "transferMethodType": "BANK_ACCOUNT" + } + ] } }, { @@ -257,29 +338,46 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "IMMEDIATE", + "country": "US", + "currency": "USD", + "transferMethodType": "BANK_CARD" + } + ] } }, { "code": "WIRE_ACCOUNT", "name": "Wire Transfer", - "processingTime": "1-3 Business days", "fees": { "nodes": [ { "country": "US", "currency": "USD", - "processingTime": "1-3 Business days", "transferMethodType": "WIRE_ACCOUNT", "value": "20.00", "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-3 Business days", + "country": "US", + "currency": "USD", + "transferMethodType": "WIRE_ACCOUNT" + } + ] } }, { "code": "PAYPAL_ACCOUNT", "name": "PayPal Account", - "processingTime": "IMMEDIATE", "fees": { "nodes": [ { @@ -290,6 +388,16 @@ "feeRateType": "FLAT" } ] + }, + "processingTimes": { + "nodes": [ + { + "value": "IMMEDIATE", + "country": "US", + "currency": "USD", + "transferMethodType": "PAYPAL_ACCOUNT" + } + ] } } ] From 68b492ab2a9a6cc45554cf401870e4fbc1b937f0 Mon Sep 17 00:00:00 2001 From: Shyang Koong Date: Thu, 11 Jul 2019 12:56:59 -0700 Subject: [PATCH 025/177] Adding scroll to espresso test (#61) --- build.gradle | 2 +- .../android/ui/receipt/ListPrepaidCardReceiptsTest.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index baab4fd0d..cf6d27824 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ subprojects { targetVersion = 28 codeVersion = 1 - hyperwalletCoreVersion = '1.0.0-beta03-SNAPSHOT' + hyperwalletCoreVersion = '1.0.0-beta03' // androidMaterialVersion = '1.0.0' appcompatVersion = '1.0.2' diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java index 20802be1c..2e9c9ff14 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java +++ b/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java @@ -165,6 +165,7 @@ public void testListPrepaidCardReceipt_userHasMultipleTransactions() { matches(atPosition(4, hasDescendant(withText("February 28, 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(4, hasDescendant(withText("USD"))))); + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.scrollToPosition(5)); onView(withId(R.id.list_receipts)).check(matches(atPosition(5, hasDescendant(withText(R.string.credit))))); onView(withId(R.id.list_receipts)).check( @@ -175,6 +176,7 @@ public void testListPrepaidCardReceipt_userHasMultipleTransactions() { matches(atPosition(5, hasDescendant(withText("February 23, 2019"))))); onView(withId(R.id.list_receipts)).check(matches(atPosition(5, hasDescendant(withText("USD"))))); + onView(withId(R.id.list_receipts)).perform(RecyclerViewActions.scrollToPosition(6)); onView(withId(R.id.list_receipts)).check(matches(atPosition(6, hasDescendant(withText(R.string.credit))))); onView(withId(R.id.list_receipts)).check( From d678348f7b0b3d24e597cf056acba0fa6098718a Mon Sep 17 00:00:00 2001 From: Peter Joseph Olamit Date: Mon, 15 Jul 2019 16:23:41 -0700 Subject: [PATCH 026/177] HW-52639 default to wallet country for tmc selection (#62) --- .../SelectTransferMethodTest.java | 39 +++ .../SelectTransferMethodContract.java | 5 +- .../SelectTransferMethodFragment.java | 4 - .../SelectTransferMethodPresenter.java | 47 ++- .../SelectTransferMethodPresenterTest.java | 103 ++++++ .../partial_success_tmc_keys_response.json | 300 ++++++++++++++++++ .../resources/user_business_response.json | 8 +- ui/src/test/resources/user_ca_response.json | 26 ++ .../resources/user_no_country_response.json | 25 ++ .../user_not_configured_country_response.json | 26 ++ ui/src/test/resources/user_response.json | 6 +- 11 files changed, 569 insertions(+), 20 deletions(-) create mode 100644 ui/src/test/resources/partial_success_tmc_keys_response.json create mode 100644 ui/src/test/resources/user_ca_response.json create mode 100644 ui/src/test/resources/user_no_country_response.json create mode 100644 ui/src/test/resources/user_not_configured_country_response.json diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java index c67aea94c..5c3ace145 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java +++ b/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java @@ -404,4 +404,43 @@ public void testSelectTransferMethod_clickBankCardOpensAddTransferMethodUi() { onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))).check( matches(withText(R.string.title_add_bank_card))); } + + @Test + public void testSelectTransferMethod_verifyThatCountryIsFromUserProfile() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_ca_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("successful_tmc_keys_response.json")).mock(); + + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.select_transfer_method_country_value)).check(matches(withText("Canada"))); + onView(withId(R.id.select_transfer_method_currency_value)).check(matches(withText("CAD"))); + } + + @Test + public void testSelectTransferMethod_verifyDefaultsToUSWhenUserProfileCountryIsNotConfigured() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_not_configured_country_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("successful_tmc_keys_response.json")).mock(); + + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.select_transfer_method_country_value)).check(matches(withText("United States"))); + onView(withId(R.id.select_transfer_method_currency_value)).check(matches(withText("USD"))); + } + + @Test + public void testSelectTransferMethod_verifyDefaultsToUSWhenUserProfileDoesNotHaveCountry() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_no_country_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("successful_tmc_keys_response.json")).mock(); + + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.select_transfer_method_country_value)).check(matches(withText("United States"))); + onView(withId(R.id.select_transfer_method_currency_value)).check(matches(withText("USD"))); + } } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodContract.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodContract.java index ec4a747fb..92e8c27bf 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodContract.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodContract.java @@ -28,6 +28,7 @@ package com.hyperwallet.android.ui.transfermethod; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.hyperwallet.android.model.HyperwalletError; @@ -89,8 +90,8 @@ interface Presenter { void loadCurrency(final boolean forceUpdate, @NonNull final String countryCode); - void loadTransferMethodConfigurationKeys(final boolean forceUpdate, @NonNull final String countryCode, - @NonNull final String currencyCode); + void loadTransferMethodConfigurationKeys(final boolean forceUpdate, @Nullable final String countryCode, + @Nullable final String currencyCode); void loadTransferMethodTypes(final boolean forceUpdate, @NonNull final String countryCode, @NonNull final String currencyCode); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java index b18a9cb93..c0e67af51 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodFragment.java @@ -55,8 +55,6 @@ public class SelectTransferMethodFragment extends Fragment implements SelectTran private static final String ARGUMENT_COUNTRY_CODE_SELECTED = "ARGUMENT_COUNTRY_CODE_SELECTED"; private static final String ARGUMENT_CURRENCY_CODE_SELECTED = "ARGUMENT_CURRENCY_CODE_SELECTED"; - private static final String DEFAULT_COUNTRY_CODE = "US"; - private static final String DEFAULT_CURRENCY_CODE = "USD"; private static final boolean FORCE_UPDATE = false; private static final String TAG = SelectTransferMethodFragment.class.getName(); @@ -80,8 +78,6 @@ public SelectTransferMethodFragment() { public static SelectTransferMethodFragment newInstance() { SelectTransferMethodFragment selectTransferMethodFragment = new SelectTransferMethodFragment(); - selectTransferMethodFragment.mSelectedCountryCode = DEFAULT_COUNTRY_CODE; - selectTransferMethodFragment.mSelectedCurrencyCode = DEFAULT_CURRENCY_CODE; Bundle arguments = new Bundle(); arguments.putString(ARGUMENT_COUNTRY_CODE_SELECTED, selectTransferMethodFragment.mSelectedCountryCode); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java index e6cb193bd..015fa8bfa 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java +++ b/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenter.java @@ -17,9 +17,14 @@ */ package com.hyperwallet.android.ui.transfermethod; +import static com.hyperwallet.android.ExceptionMapper.EC_UNEXPECTED_EXCEPTION; + +import android.text.TextUtils; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationKey; import com.hyperwallet.android.model.graphql.keyed.Country; @@ -30,6 +35,7 @@ import com.hyperwallet.android.ui.repository.UserRepository; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -37,6 +43,8 @@ public class SelectTransferMethodPresenter implements SelectTransferMethodContract.Presenter { + private static final String DEFAULT_COUNTRY_CODE = "US"; + private final TransferMethodConfigurationRepository mTransferMethodConfigurationRepository; private final UserRepository mUserRepository; private final SelectTransferMethodContract.View mView; @@ -50,8 +58,8 @@ public class SelectTransferMethodPresenter implements SelectTransferMethodContra } @Override - public void loadTransferMethodConfigurationKeys(final boolean forceUpdate, @NonNull final String countryCode, - @NonNull final String currencyCode) { + public void loadTransferMethodConfigurationKeys(final boolean forceUpdate, @Nullable final String countryCode, + @Nullable final String currencyCode) { mView.showProgressBar(); @@ -69,16 +77,41 @@ public void onKeysLoaded(@Nullable final HyperwalletTransferMethodConfigurationK if (!mView.isActive()) { return; } + + Country country = TextUtils.isEmpty(countryCode) ? key.getCountry(user.getCountry()) + : key.getCountry(countryCode); + + if (country == null) { // param and user country is null + country = key.getCountry(DEFAULT_COUNTRY_CODE); + } + + String currencyCodeString = currencyCode; + Set currencies = key.getCurrencies(country.getCode()); + if (TextUtils.isEmpty(currencyCodeString) && currencies != null + && !currencies.isEmpty()) { + currencyCodeString = ((Currency) currencies.toArray()[0]).getCode(); + } + + // at this point if currencyCodeString is still null/empty, that means program is + // mis-configured + if (TextUtils.isEmpty(currencyCodeString)) { + HyperwalletError error = new HyperwalletError( + "Can't get Currency based from Country: " + country.getCode(), + EC_UNEXPECTED_EXCEPTION); + showErrorLoadTransferMethods(new HyperwalletErrors(Arrays.asList(error))); + return; + } + mView.hideProgressBar(); Set transferMethodTypes = - key.getTransferMethodType(countryCode, currencyCode) != null - ? key.getTransferMethodType(countryCode, currencyCode) : + key.getTransferMethodType(country.getCode(), currencyCodeString) != null + ? key.getTransferMethodType(country.getCode(), currencyCodeString) : new HashSet(); - mView.showTransferMethodCountry(countryCode); - mView.showTransferMethodCurrency(currencyCode); + mView.showTransferMethodCountry(country.getCode()); + mView.showTransferMethodCurrency(currencyCodeString); mView.showTransferMethodTypes( - getTransferMethodSelectionItems(countryCode, currencyCode, + getTransferMethodSelectionItems(country.getCode(), currencyCodeString, user.getProfileType(), transferMethodTypes)); } diff --git a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java index 9a109230a..d90192572 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java +++ b/ui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java @@ -1,5 +1,7 @@ package com.hyperwallet.android.ui.transfermethod; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -11,6 +13,8 @@ import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; +import static com.hyperwallet.android.ExceptionMapper.EC_UNEXPECTED_EXCEPTION; + import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationKey; @@ -23,12 +27,15 @@ import com.hyperwallet.android.ui.repository.UserRepositoryImpl; import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; +import org.hamcrest.Matchers; import org.json.JSONObject; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -50,7 +57,11 @@ public class SelectTransferMethodPresenterTest { private TransferMethodConfigurationRepositoryImpl mTransferMethodConfigurationRepository; @Mock private UserRepositoryImpl mUserRepository; + @Captor + private ArgumentCaptor> mErrorCaptor; + private HyperwalletTransferMethodConfigurationKey mResult; + private HyperwalletTransferMethodConfigurationKey mPartialResult; private HyperwalletUser mUser; private SelectTransferMethodPresenter selectTransferMethodPresenter; @@ -61,6 +72,10 @@ public void initialize() throws Exception { final JSONObject jsonObject = new JSONObject(responseBody); mResult = new HyperwalletTransferMethodConfigurationKeyResult(jsonObject); + String partialResponseBody = externalResourceManager.getResourceContent( + "partial_success_tmc_keys_response.json"); + mPartialResult = new HyperwalletTransferMethodConfigurationKeyResult(new JSONObject(partialResponseBody)); + String userResponseBody = externalResourceManager.getResourceContent("user_response.json"); final JSONObject userJsonObject = new JSONObject(userResponseBody); mUser = new HyperwalletUser(userJsonObject); @@ -187,6 +202,94 @@ public Object answer(InvocationOnMock invocation) { verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); } + @Test + public void testLoadTransferMethodConfigurationKeys_loadsKeysIntoUserProfileCountryViewOnSuccess() { + // When + when(view.isActive()).thenReturn(true); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + TransferMethodConfigurationRepository.LoadKeysCallback callback = + (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; + callback.onKeysLoaded(mResult); + return callback; + } + }).when(mTransferMethodConfigurationRepository).getKeys(any( + TransferMethodConfigurationRepository.LoadKeysCallback.class)); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + + // Then + selectTransferMethodPresenter.loadTransferMethodConfigurationKeys(false, null, null); + + verify(view).showTransferMethodCountry("US"); + verify(view).showTransferMethodCurrency("USD"); + verify(view).showTransferMethodTypes(ArgumentMatchers.anyList()); + verify(view, never()).showErrorLoadTransferMethodConfigurationKeys( + ArgumentMatchers.anyList()); + verify(view, never()).showErrorLoadCurrency(ArgumentMatchers.anyList()); + verify(view, never()).showErrorLoadTransferMethodTypes(ArgumentMatchers.anyList()); + verify(view, never()).showErrorLoadCountrySelection(ArgumentMatchers.anyList()); + verify(view, never()).showErrorLoadCurrencySelection(ArgumentMatchers.anyList()); + verify(view, never()).showAddTransferMethod(anyString(), anyString(), anyString(), anyString()); + } + + @Test + public void testLoadTransferMethodConfigurationKeys_loadsKeysIntoUserProfileCountryViewOnError() { + // When + when(view.isActive()).thenReturn(true); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + TransferMethodConfigurationRepository.LoadKeysCallback callback = + (TransferMethodConfigurationRepository.LoadKeysCallback) invocation.getArguments()[0]; + callback.onKeysLoaded(mPartialResult); + return callback; + } + }).when(mTransferMethodConfigurationRepository).getKeys(any( + TransferMethodConfigurationRepository.LoadKeysCallback.class)); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + UserRepository.LoadUserCallback userCallback = + (UserRepository.LoadUserCallback) invocation.getArguments()[0]; + userCallback.onUserLoaded(mUser); + return userCallback; + } + }).when(mUserRepository).loadUser(any( + UserRepository.LoadUserCallback.class)); + + // Then + selectTransferMethodPresenter.loadTransferMethodConfigurationKeys(false, null, null); + + + verify(view).showProgressBar(); + verify(view, times(2)).isActive(); + verify(view).hideProgressBar(); + verify(view).showErrorLoadTransferMethodConfigurationKeys(mErrorCaptor.capture()); + verify(view, never()).showTransferMethodCountry(anyString()); + verify(view, never()).showTransferMethodCurrency(anyString()); + verify(view, never()).showTransferMethodTypes(ArgumentMatchers.anyList()); + + // Assert + List errors = mErrorCaptor.getValue(); + assertThat(errors, Matchers.hasSize(1)); + assertThat(errors.get(0).getCode(), is(EC_UNEXPECTED_EXCEPTION)); + assertThat(errors.get(0).getMessage(), is("Can't get Currency based from Country: US")); + } + @Test public void testLoadCurrency_loadsCurrenciesIntoViewOnSuccess() { // When diff --git a/ui/src/test/resources/partial_success_tmc_keys_response.json b/ui/src/test/resources/partial_success_tmc_keys_response.json new file mode 100644 index 000000000..14c93e060 --- /dev/null +++ b/ui/src/test/resources/partial_success_tmc_keys_response.json @@ -0,0 +1,300 @@ +{ + "data": { + "countries": { + "nodes": [ + { + "code": "CA", + "name": "Canada", + "currencies": { + "nodes": [ + { + "code": "CAD", + "name": "Canadian Dollar", + "transferMethodTypes": { + "nodes": [ + { + "code": "BANK_ACCOUNT", + "name": "Bank Account", + "fees": { + "nodes": [ + { + "country": "CA", + "currency": "CAD", + "transferMethodType": "BANK_ACCOUNT", + "value": "2.20", + "feeRateType": "FLAT" + } + ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "CA", + "currency": "CAD", + "transferMethodType": "BANK_ACCOUNT" + } + ] + } + }, + { + "code": "PAYPAL_ACCOUNT", + "name": "PayPal Account", + "fees": { + "nodes": [ + { + "country": "CA", + "currency": "CAD", + "transferMethodType": "PAYPAL_ACCOUNT", + "value": "0.25", + "feeRateType": "FLAT" + } + ] + }, + "processingTimes": { + "nodes": [ + { + "value": "IMMEDIATE", + "country": "CA", + "currency": "CAD", + "transferMethodType": "PAYPAL_ACCOUNT" + } + ] + } + } + ] + } + }, + { + "code": "USD", + "name": "United States Dollar", + "transferMethodTypes": { + "nodes": [ + { + "code": "BANK_ACCOUNT", + "name": "Bank Account", + "fees": { + "nodes": [ + { + "country": "CA", + "currency": "USD", + "transferMethodType": "BANK_ACCOUNT", + "value": "2.00", + "feeRateType": "FLAT" + } + ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "CA", + "currency": "USD", + "transferMethodType": "BANK_ACCOUNT" + } + ] + } + } + ] + } + } + ] + } + }, + { + "code": "HR", + "name": "Croatia", + "currencies": { + "nodes": [ + { + "code": "EUR", + "name": "Euro", + "transferMethodTypes": { + "nodes": [ + { + "code": "BANK_ACCOUNT", + "name": "Bank Account", + "fees": { + "nodes": [ + { + "country": "HR", + "currency": "EUR", + "transferMethodType": "BANK_ACCOUNT", + "value": "1.50", + "feeRateType": "FLAT" + } + ] + }, + "processingTimes": { + "nodes": [ + { + "value": "2-3 Business days", + "country": "HR", + "currency": "EUR", + "transferMethodType": "BANK_ACCOUNT" + } + ] + } + } + ] + } + }, + { + "code": "HRK", + "name": "Croatian Kuna", + "transferMethodTypes": { + "nodes": [ + { + "code": "BANK_ACCOUNT", + "name": "Bank Account", + "fees": { + "nodes": [ + { + "country": "HR", + "currency": "HRK", + "transferMethodType": "BANK_ACCOUNT", + "value": "1.50", + "feeRateType": "FLAT" + } + ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "HR", + "currency": "HRK", + "transferMethodType": "BANK_ACCOUNT" + } + ] + } + } + ] + } + } + ] + } + }, + { + "code": "MX", + "name": "Mexico", + "currencies": { + "nodes": [ + { + "code": "MXN", + "name": "Mexican Peso", + "transferMethodTypes": { + "nodes": [ + { + "code": "BANK_ACCOUNT", + "name": "Bank Account", + "fees": { + "nodes": [ + { + "country": "MX", + "currency": "MXN", + "transferMethodType": "BANK_ACCOUNT", + "value": "26.15", + "feeRateType": "FLAT" + } + ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "MX", + "currency": "MXN", + "transferMethodType": "BANK_ACCOUNT" + } + ] + } + } + ] + } + } + ] + } + }, + { + "code": "GB", + "name": "United Kingdom", + "currencies": { + "nodes": [ + { + "code": "EUR", + "name": "Euro", + "transferMethodTypes": { + "nodes": [ + { + "code": "BANK_ACCOUNT", + "name": "Bank Account", + "fees": { + "nodes": [ + { + "country": "GB", + "currency": "EUR", + "transferMethodType": "BANK_ACCOUNT", + "value": "1.50", + "feeRateType": "FLAT" + } + ] + }, + "processingTimes": { + "nodes": [ + { + "value": "2-4 Business days", + "country": "GB", + "currency": "EUR", + "transferMethodType": "BANK_ACCOUNT" + } + ] + } + } + ] + } + }, + { + "code": "GBP", + "name": "British Pound", + "transferMethodTypes": { + "nodes": [ + { + "code": "BANK_ACCOUNT", + "name": "Bank Account", + "fees": { + "nodes": [ + { + "country": "GB", + "currency": "GBP", + "transferMethodType": "BANK_ACCOUNT", + "value": "1.20", + "feeRateType": "FLAT" + } + ] + }, + "processingTimes": { + "nodes": [ + { + "value": "1-2 Business days", + "country": "GB", + "currency": "GBP", + "transferMethodType": "BANK_ACCOUNT" + } + ] + } + } + ] + } + } + ] + } + }, + { + "code": "US", + "name": "United States" + } + ] + } + } +} \ No newline at end of file diff --git a/ui/src/test/resources/user_business_response.json b/ui/src/test/resources/user_business_response.json index 5ba6c60e2..02b57af6d 100644 --- a/ui/src/test/resources/user_business_response.json +++ b/ui/src/test/resources/user_business_response.json @@ -1,5 +1,5 @@ { - "token": "usr-e602a937-334c-49e5-b37e-4c842c1cc7a1", + "token": "usr-token-1", "status": "PRE_ACTIVATED", "verificationStatus": "NOT_REQUIRED", "createdOn": "2019-05-14T21:51:15", @@ -28,17 +28,17 @@ "addressLine2": "second floor", "city": "Burnaby", "stateProvince": "XZ", - "country": "CA", + "country": "US", "postalCode": "v5z3a2", "language": "en", "timeZone": "GMT", - "programToken": "prg-7a2441be-1b00-4239-b2d6-623a0eb8f160", + "programToken": "prg-token-1", "links": [ { "params": { "rel": "self" }, - "href": "https://api.sandbox.hyperwallet.com/rest/v3/users/usr-e602a937-334c-49e5-b37e-4c842c1cc7a1" + "href": "https://localhost/rest/v3/users/usr-token-1" } ] } \ No newline at end of file diff --git a/ui/src/test/resources/user_ca_response.json b/ui/src/test/resources/user_ca_response.json new file mode 100644 index 000000000..4d771cc49 --- /dev/null +++ b/ui/src/test/resources/user_ca_response.json @@ -0,0 +1,26 @@ +{ + "token": "usr-token-2", + "status": "PRE_ACTIVATED", + "createdOn": "2017-10-30T22:15:45", + "clientUserId": "123456", + "profileType": "INDIVIDUAL", + "firstName": "Person", + "lastName": "FromCanada", + "dateOfBirth": "1991-01-01", + "email": "user+4satF1xV@hyperwallet.com", + "addressLine1": "950 Granville", + "city": "Vancouver", + "stateProvince": "BC", + "country": "CA", + "postalCode": "H0H0H0", + "language": "en", + "programToken": "prg-token-2", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost/rest/v3/users/usr-token-2" + } + ] +} \ No newline at end of file diff --git a/ui/src/test/resources/user_no_country_response.json b/ui/src/test/resources/user_no_country_response.json new file mode 100644 index 000000000..cb0586fd2 --- /dev/null +++ b/ui/src/test/resources/user_no_country_response.json @@ -0,0 +1,25 @@ +{ + "token": "usr-token-3", + "status": "PRE_ACTIVATED", + "createdOn": "2017-10-30T22:15:45", + "clientUserId": "123456", + "profileType": "INDIVIDUAL", + "firstName": "Person", + "lastName": "FromNoCountry", + "dateOfBirth": "1991-01-01", + "email": "user+4satF1xV@hyperwallet.com", + "addressLine1": "950 Granville", + "city": "Vancouver", + "stateProvince": "BC", + "postalCode": "H0H0H0", + "language": "en", + "programToken": "prg-token-3", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost/rest/v3/users/usr-token-3" + } + ] +} \ No newline at end of file diff --git a/ui/src/test/resources/user_not_configured_country_response.json b/ui/src/test/resources/user_not_configured_country_response.json new file mode 100644 index 000000000..9c65d0375 --- /dev/null +++ b/ui/src/test/resources/user_not_configured_country_response.json @@ -0,0 +1,26 @@ +{ + "token": "usr-token-4", + "status": "PRE_ACTIVATED", + "createdOn": "2017-10-30T22:15:45", + "clientUserId": "123456", + "profileType": "INDIVIDUAL", + "firstName": "Person", + "lastName": "FromJapan", + "dateOfBirth": "1991-01-01", + "email": "user+4satF1xV@hyperwallet.com", + "addressLine1": "950 Granville", + "city": "Vancouver", + "stateProvince": "BC", + "country": "JP", + "postalCode": "H0H0H0", + "language": "en", + "programToken": "prg-token-4", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost/rest/v3/users/usr-token-4" + } + ] +} \ No newline at end of file diff --git a/ui/src/test/resources/user_response.json b/ui/src/test/resources/user_response.json index e65074bef..018ea339e 100644 --- a/ui/src/test/resources/user_response.json +++ b/ui/src/test/resources/user_response.json @@ -1,5 +1,5 @@ { - "token": "usr-f9154016-94e8-4686-a840-075688ac07b5", + "token": "usr-token-5", "status": "PRE_ACTIVATED", "createdOn": "2017-10-30T22:15:45", "clientUserId": "123456", @@ -14,13 +14,13 @@ "country": "US", "postalCode": "94105", "language": "en", - "programToken": "prg-83836cdf-2ce2-4696-8bc5-f1b86077238c", + "programToken": "prg-token-5", "links": [ { "params": { "rel": "self" }, - "href": "https://api.sandbox.hyperwallet.com/rest/v3/users/usr-f9154016-94e8-4686-a840-075688ac07b5" + "href": "https://localhost/rest/v3/users/usr-token-5" } ] } \ No newline at end of file From 49dd77e646b26482628e1f899b9ec4c2ecd8ec2d Mon Sep 17 00:00:00 2001 From: Anna <48258136+azakrevska-epam@users.noreply.github.com> Date: Mon, 22 Jul 2019 21:51:28 +0300 Subject: [PATCH 027/177] HW-54223 multi project (#57) --- .gitignore | 7 +- android-library.gradle | 9 +- {common => commonrepository}/.gitignore | 0 commonrepository/build.gradle | 7 + .../config/jacoco-settings.gradle | 82 ++ {common => commonrepository}/config/lint.xml | 0 .../proguard-rules.pro | 0 commonrepository/src/main/AndroidManifest.xml | 1 + .../repository}/EspressoIdlingResource.java | 2 +- .../android/ui/common/repository}/Event.java | 2 +- {receipt => commonui}/.gitignore | 0 commonui/build.gradle | 10 + .../config/jacoco-settings.gradle | 4 +- commonui/config/lint.xml | 7 + {receipt => commonui}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../android/ui/common/util/DateUtils.java | 0 .../view/HorizontalDividerItemDecorator.java | 0 .../ui/common/view/OneClickListener.java | 0 .../error/DefaultErrorDialogFragment.java | 0 .../DefaultErrorDialogFragmentContract.java | 0 .../DefaultErrorDialogFragmentPresenter.java | 0 .../view/error/OnNetworkErrorCallback.java | 0 .../common/viewmodel/ListDetailNavigator.java | 4 +- .../src/main/res/drawable/circle.xml | 0 .../src/main/res/drawable/circle_white.xml | 0 .../res/drawable/content_border_bottom.xml | 0 .../drawable/content_border_top_bottom.xml | 0 .../main/res/drawable/horizontal_divider.xml | 0 .../drawable/ic_baseline_bug_report_24px.xml | 0 .../drawable/ic_baseline_cloud_off_24px.xml | 0 .../res/drawable/ic_baseline_warning_24px.xml | 0 .../src/main/res/drawable/ic_check_14dp.xml | 0 .../src/main/res/drawable/ic_close_14dp.xml | 0 .../drawable/ic_keyboard_arrow_down_12dp.xml | 0 .../drawable/ic_keyboard_arrow_left_12dp.xml | 0 .../drawable/ic_keyboard_arrow_right_12dp.xml | 0 .../res/drawable/ic_launcher_background.xml | 0 .../main/res/drawable/ic_placeholder_24dp.xml | 0 .../src/main/res/drawable/ic_search_24dp.xml | 0 .../main/res/drawable/ic_three_dots_16dp.xml | 0 .../src/main/res/drawable/ic_trash.xml | 0 .../src/main/res/drawable/oval.xml | 0 .../res/drawable/view_border_top_bottom.xml | 0 .../main/res/drawable/view_item_ripple.xml | 0 .../src/main/res/font/icomoon.ttf | Bin .../src/main/res/values/colors.xml | 0 .../src/main/res/values/dimens.xml | 0 .../src/main/res/values/strings.xml | 0 .../src/main/res/values/styles.xml | 0 .../android/ui/common/util/DateUtilsTest.java | 0 ...faultErrorDialogFragmentPresenterTest.java | 0 common/build.gradle => publish.gradle | 24 +- receipt/build.gradle | 111 -- receiptrepository/.gitignore | 1 + receiptrepository/build.gradle | 16 + .../config/jacoco-settings.gradle | 79 ++ .../config/lint.xml | 0 .../src/main/AndroidManifest.xml | 4 + .../PrepaidCardReceiptDataSource.java | 4 +- .../PrepaidCardReceiptDataSourceFactory.java | 0 .../PrepaidCardReceiptRepository.java | 3 +- .../PrepaidCardReceiptRepositoryImpl.java | 2 +- .../repository/UserReceiptDataSource.java | 10 +- .../UserReceiptDataSourceFactory.java | 0 .../repository/UserReceiptRepository.java | 2 +- .../repository/UserReceiptRepositoryImpl.java | 6 +- ...epaidCardReceiptDataSourceFactoryTest.java | 0 .../PrepaidCardReceiptDataSourceTest.java | 10 +- .../PrepaidCardReceiptRepositoryImplTest.java | 2 +- .../UserReceiptDataSourceFactoryTest.java | 0 .../repository/UserReceiptDataSourceTest.java | 9 +- .../UserReceiptRepositoryImplTest.java | 2 +- .../HyperwalletExternalResourceManager.java | 2 +- .../prepaid_card_receipt_list_response.json | 0 .../receipt_list_date_grouping_response.json | 0 receiptui/.gitignore | 1 + receiptui/build.gradle | 25 + .../config/jacoco-settings.gradle | 3 +- receiptui/config/lint.xml | 10 + {ui => receiptui}/proguard-rules.pro | 0 .../src/androidTest/AndroidManifest.xml | 0 ...yperwalletInstrumentedTestApplication.java | 0 .../receipt/ListPrepaidCardReceiptsTest.java | 6 +- .../ui/receipt/ListUserReceiptsTest.java | 4 +- .../HyperwalletExternalResourceManager.java | 0 .../rule/HyperwalletMockWebServer.java | 0 .../ui/receipt/util/EspressoUtils.java | 0 .../ui/receipt/util/NestedScrollToAction.java | 0 .../util/RecyclerViewCountAssertion.java | 0 .../util/TestAuthenticationProvider.java | 0 .../src/main/AndroidManifest.xml | 0 .../ui/receipt/HyperwalletReceiptUi.java | 68 + .../view/ListPrepaidCardReceiptActivity.java | 2 +- .../ui/receipt/view/ListReceiptFragment.java | 0 .../receipt/view/ListUserReceiptActivity.java | 2 +- .../receipt/view/ReceiptDetailActivity.java | 0 .../receipt/view/ReceiptDetailFragment.java | 0 .../view/ReceiptItemDividerDecorator.java | 0 .../ListPrepaidCardReceiptViewModel.java | 2 +- .../viewmodel/ListUserReceiptViewModel.java | 10 +- .../viewmodel/ReceiptDetailViewModel.java | 0 .../receipt/viewmodel/ReceiptViewModel.java | 2 +- .../src/main/res/drawable/circle_negative.xml | 0 .../src/main/res/drawable/circle_positive.xml | 0 .../main/res/drawable/item_view_border.xml | 0 .../res/drawable/item_view_border_header.xml | 0 .../activity_list_prepaid_card_receipt.xml | 0 .../res/layout/activity_list_user_receipt.xml | 0 .../res/layout/activity_receipt_detail.xml | 0 .../main/res/layout/fragment_list_receipt.xml | 0 .../res/layout/fragment_receipt_detail.xml | 0 .../src/main/res/layout/item_receipt.xml | 0 .../res/layout/item_receipt_with_header.xml | 0 .../src/main/res/layout/receipt.xml | 0 .../src/main/res/values/colors.xml | 0 .../src/main/res/values/dimens.xml | 0 .../src/main/res/values/strings.xml | 0 .../src/main/res/values/styles.xml | 0 .../main/res/xml/network_security_config.xml | 0 .../HyperwalletExternalResourceManager.java | 3 +- .../authentication_token_response.json | 0 .../prepaid_card_receipt_credit_response.json | 0 .../prepaid_card_receipt_debit_response.json | 0 .../prepaid_card_receipt_list_response.json | 103 ++ ...id_card_receipt_unknown_type_response.json | 0 .../resources/receipt_credit_response.json | 0 .../resources/receipt_debit_response.json | 0 .../receipt_list_date_grouping_response.json | 90 ++ .../receipt_list_paged_last_response.json | 0 .../receipt_list_paged_response.json | 0 .../receipt_list_paged_second_response.json | 0 .../receipt_list_paged_third_response.json | 0 .../test/resources/receipt_list_response.json | 0 .../receipt_unknown_type_response.json | 0 settings.gradle | 2 +- transfermethodrepository/.gitignore | 3 + transfermethodrepository/build.gradle | 12 + .../config/jacoco-settings.gradle | 78 + transfermethodrepository/config/lint.xml | 6 + transfermethodrepository/proguard-rules.pro | 21 + .../src/main/AndroidManifest.xml | 2 + ...TransferMethodConfigurationRepository.java | 2 +- ...sferMethodConfigurationRepositoryImpl.java | 17 +- .../repository/TransferMethodRepository.java | 2 +- .../TransferMethodRepositoryFactory.java | 47 + .../TransferMethodRepositoryImpl.java | 2 +- .../repository/FieldMapKeyTest.java | 2 +- ...MethodConfigurationRepositoryImplTest.java | 4 +- .../TransferMethodRepositoryFactoryTest.java | 30 +- .../TransferMethodRepositoryImplTest.java | 2 +- .../HyperwalletExternalResourceManager.java | 2 +- .../resources/error_tmc_keys_response.json | 0 ...sful_tmc_fields_bank_account_response.json | 0 .../successful_tmc_keys_response.json | 0 {ui => transfermethodui}/.gitignore | 0 transfermethodui/build.gradle | 29 + .../config/jacoco-settings.gradle | 14 +- {ui => transfermethodui}/config/lint.xml | 0 transfermethodui/proguard-rules.pro | 21 + .../src/androidTest/AndroidManifest.xml | 2 +- .../transfermethod/AddTransferMethodTest.java | 15 +- .../ui/transfermethod/BankAccountTest.java | 25 +- .../ui/transfermethod/BankCardTest.java | 21 +- ...yperwalletInstrumentedTestApplication.java | 2 +- .../ListTransferMethodTest.java | 17 +- .../android/ui/transfermethod/PayPalTest.java | 21 +- .../SelectTransferMethodTest.java | 29 +- .../HyperwalletExternalResourceManager.java | 73 + .../rule/HyperwalletMockWebServer.java | 2 +- .../transfermethod}/util/EspressoUtils.java | 2 +- .../util/NestedScrollToAction.java | 2 +- .../util/RecyclerViewCountAssertion.java | 2 +- .../util/TestAuthenticationProvider.java | 2 +- .../src/main/AndroidManifest.xml | 6 +- ...perwalletTransferMethodLocalBroadcast.java | 8 +- .../HyperwalletTransferMethodUi.java | 57 +- .../view}/AddTransferMethodActivity.java | 4 +- .../view}/AddTransferMethodContract.java | 2 +- .../view}/AddTransferMethodFragment.java | 46 +- .../view}/AddTransferMethodPresenter.java | 6 +- .../view/CountrySelectionDialogFragment.java | 2 +- .../view/CurrencySelectionDialogFragment.java | 2 +- .../ui/transfermethod/view}/FeeFormatter.java | 2 +- .../view}/ListTransferMethodActivity.java | 4 +- .../view}/ListTransferMethodContract.java | 2 +- .../view}/ListTransferMethodFragment.java | 16 +- .../view}/ListTransferMethodPresenter.java | 4 +- .../OnTransferMethodDeactivateCallback.java | 2 +- .../view}/SelectTransferMethodActivity.java | 4 +- .../view}/SelectTransferMethodContract.java | 2 +- .../view}/SelectTransferMethodFragment.java | 16 +- .../view}/SelectTransferMethodPresenter.java | 8 +- .../view/ToolbarEventListener.java | 2 +- ...thodConfirmDeactivationDialogFragment.java | 2 +- .../view}/TransferMethodSelectionItem.java | 2 +- .../view}/TransferMethodUtils.java | 2 +- .../view/WidgetDateDialogFragment.java | 6 +- .../view/WidgetSelectionDialogFragment.java | 2 +- .../view/widget/AbstractWidget.java | 2 +- .../view/widget/DateChangedListener.java | 2 +- .../view/widget/DateUtils.java | 2 +- .../view/widget/DateWidget.java | 2 +- .../view/widget/DefaultAccountWidget.java | 2 +- .../view/widget/ExpireDateUtils.java | 2 +- .../view/widget/ExpiryDateWidget.java | 10 +- .../view/widget/NumberWidget.java | 2 +- .../view/widget/PhoneWidget.java | 2 +- .../view/widget/SelectionWidget.java | 4 +- .../view/widget/TextWidget.java | 2 +- .../view/widget/WidgetEventListener.java | 2 +- .../view/widget/WidgetFactory.java | 2 +- .../view/widget/WidgetInputState.java | 2 +- .../layout/activity_add_transfer_method.xml | 4 +- .../layout/activity_list_transfer_method.xml | 4 +- .../activity_select_transfer_method.xml | 2 +- .../dialog_fragment_country_selection.xml | 0 .../dialog_fragment_currency_selection.xml | 0 .../dialog_fragment_widget_selection.xml | 0 .../layout/fragment_add_transfer_method.xml | 2 +- .../layout/fragment_list_transfer_method.xml | 2 +- .../fragment_select_transfer_method.xml | 2 +- .../src/main/res/layout/item_country.xml | 0 .../src/main/res/layout/item_currency.xml | 0 .../res/layout/item_transfer_method_type.xml | 0 .../main/res/layout/item_widget_layout.xml | 0 .../res/layout/item_widget_section_header.xml | 0 .../main/res/layout/item_widget_selection.xml | 0 .../main/res/menu/menu_country_selection.xml | 0 .../main/res/menu/menu_currency_selection.xml | 0 .../main/res/menu/menu_widget_selection.xml | 0 .../res/menu/transfer_method_context_menu.xml | 0 .../mipmap-hdpi/ic_launcher_foreground.png | Bin .../mipmap-mdpi/ic_launcher_foreground.png | Bin .../mipmap-xhdpi/ic_launcher_foreground.png | Bin .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin .../res/values/ic_launcher_background.xml | 0 .../src/main/res/values/ids.xml | 0 .../src/main/res/values/strings.xml | 0 .../src/main/res/values/styles.xml | 0 .../main/res/xml/network_security_config.xml | 0 .../src/main/res/xml/searchable.xml | 0 .../AddTransferMethodPresenterTest.java | 8 +- .../ui/transfermethod/FeeFormatterTest.java | 3 +- .../ListTransferMethodPresenterTest.java | 4 +- .../SelectTransferMethodPresenterTest.java | 13 +- .../TransferMethodUtilsTest.java | 5 +- .../HyperwalletExternalResourceManager.java | 74 + .../view/widget/DateUtilsTest.java | 5 +- .../view/widget/ExpireDateUtilsTest.java | 2 +- .../add_transfer_method_presenter_test.json | 0 .../authentication_token_response.json | 0 ...nk_account_duplicate_routing_response.json | 0 ...bank_account_invalid_routing_response.json | 0 .../test/resources/bank_account_response.json | 0 .../test/resources/bank_card_response.json | 0 ...on_validation_error_test_diff_min_max.json | 0 ...on_validation_error_test_same_min_max.json | 0 .../resources/error_bank_card_response.json | 0 .../resources/error_tmc_fields_response.json | 0 .../resources/error_tmc_keys_response.json | 13 + .../src/test/resources/fee_information.json | 0 .../test/resources/invalid_json_response.json | 0 .../partial_success_tmc_keys_response.json | 0 .../paypal_invalid_email_response.json | 0 .../src/test/resources/paypal_response.json | 0 ...sful_tmc_fields_bank_account_response.json | 1250 +++++++++++++++++ ...cessful_tmc_fields_bank_card_response.json | 0 ...ful_tmc_fields_empty_details_response.json | 0 ...successful_tmc_fields_paypal_response.json | 0 ...uccessful_tmc_keys_empty_fee_response.json | 0 ...ul_tmc_keys_empty_processing_response.json | 0 .../successful_tmc_keys_large_response.json | 0 .../successful_tmc_keys_response.json | 412 ++++++ .../transfer_method_deactivate_success.json | 0 ...transfer_method_list_deleted_response.json | 0 .../transfer_method_list_response.json | 0 ...hod_list_single_bank_account_response.json | 0 ...method_list_single_bank_card_response.json | 0 ...d_list_single_paypal_account_response.json | 0 .../resources/user_business_response.json | 0 .../src/test/resources/user_ca_response.json | 0 .../resources/user_no_country_response.json | 0 .../user_not_configured_country_response.json | 0 .../src/test/resources/user_response.json | 0 ui/build.gradle | 113 -- .../ui/repository/RepositoryFactory.java | 64 - userrepository/.gitignore | 1 + userrepository/build.gradle | 11 + userrepository/config/jacoco-settings.gradle | 78 + userrepository/config/lint.xml | 6 + userrepository/proguard-rules.pro | 21 + userrepository/src/main/AndroidManifest.xml | 2 + .../ui/user}/repository/UserRepository.java | 5 +- .../repository/UserRepositoryFactory.java | 25 + .../user}/repository/UserRepositoryImpl.java | 2 +- .../repository/UserRepositoryFactoryTest.java | 34 + .../repository/UserRepositoryImplTest.java | 8 +- 299 files changed, 3054 insertions(+), 634 deletions(-) rename {common => commonrepository}/.gitignore (100%) create mode 100644 commonrepository/build.gradle create mode 100644 commonrepository/config/jacoco-settings.gradle rename {common => commonrepository}/config/lint.xml (100%) rename {common => commonrepository}/proguard-rules.pro (100%) create mode 100644 commonrepository/src/main/AndroidManifest.xml rename {common/src/main/java/com/hyperwallet/android/ui/common/util => commonrepository/src/main/java/com/hyperwallet/android/ui/common/repository}/EspressoIdlingResource.java (91%) rename {common/src/main/java/com/hyperwallet/android/ui/common/viewmodel => commonrepository/src/main/java/com/hyperwallet/android/ui/common/repository}/Event.java (97%) rename {receipt => commonui}/.gitignore (100%) create mode 100644 commonui/build.gradle rename {common => commonui}/config/jacoco-settings.gradle (92%) create mode 100644 commonui/config/lint.xml rename {receipt => commonui}/proguard-rules.pro (100%) rename {common => commonui}/src/main/AndroidManifest.xml (100%) rename {common => commonui}/src/main/java/com/hyperwallet/android/ui/common/util/DateUtils.java (100%) rename {common => commonui}/src/main/java/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.java (100%) rename {common => commonui}/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java (100%) rename {common => commonui}/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.java (100%) rename {common => commonui}/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentContract.java (100%) rename {common => commonui}/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenter.java (100%) rename {common => commonui}/src/main/java/com/hyperwallet/android/ui/common/view/error/OnNetworkErrorCallback.java (100%) rename {common => commonui}/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java (94%) rename {common => commonui}/src/main/res/drawable/circle.xml (100%) rename {common => commonui}/src/main/res/drawable/circle_white.xml (100%) rename {common => commonui}/src/main/res/drawable/content_border_bottom.xml (100%) rename {common => commonui}/src/main/res/drawable/content_border_top_bottom.xml (100%) rename {common => commonui}/src/main/res/drawable/horizontal_divider.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_baseline_bug_report_24px.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_baseline_cloud_off_24px.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_baseline_warning_24px.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_check_14dp.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_close_14dp.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_launcher_background.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_placeholder_24dp.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_search_24dp.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_three_dots_16dp.xml (100%) rename {common => commonui}/src/main/res/drawable/ic_trash.xml (100%) rename {common => commonui}/src/main/res/drawable/oval.xml (100%) rename {common => commonui}/src/main/res/drawable/view_border_top_bottom.xml (100%) rename {common => commonui}/src/main/res/drawable/view_item_ripple.xml (100%) rename {common => commonui}/src/main/res/font/icomoon.ttf (100%) rename {common => commonui}/src/main/res/values/colors.xml (100%) rename {common => commonui}/src/main/res/values/dimens.xml (100%) rename {common => commonui}/src/main/res/values/strings.xml (100%) rename {common => commonui}/src/main/res/values/styles.xml (100%) rename {common => commonui}/src/test/java/com/hyperwallet/android/ui/common/util/DateUtilsTest.java (100%) rename {common => commonui}/src/test/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenterTest.java (100%) rename common/build.gradle => publish.gradle (79%) delete mode 100644 receipt/build.gradle create mode 100644 receiptrepository/.gitignore create mode 100644 receiptrepository/build.gradle create mode 100644 receiptrepository/config/jacoco-settings.gradle rename {receipt => receiptrepository}/config/lint.xml (100%) create mode 100644 receiptrepository/src/main/AndroidManifest.xml rename {receipt => receiptrepository}/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java (98%) rename {receipt => receiptrepository}/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactory.java (100%) rename {receipt => receiptrepository}/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java (97%) rename {receipt => receiptrepository}/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java (97%) rename {receipt => receiptrepository}/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java (98%) rename {receipt => receiptrepository}/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactory.java (100%) rename {receipt => receiptrepository}/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java (97%) rename {receipt => receiptrepository}/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java (97%) rename {receipt => receiptrepository}/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactoryTest.java (100%) rename {receipt => receiptrepository}/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java (99%) rename {receipt => receiptrepository}/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java (97%) rename {receipt => receiptrepository}/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactoryTest.java (100%) rename {receipt => receiptrepository}/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java (99%) rename {receipt => receiptrepository}/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java (97%) rename {receipt/src/test/java/com/hyperwallet/android/ui => receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt}/rule/HyperwalletExternalResourceManager.java (98%) rename {receipt => receiptrepository}/src/test/resources/prepaid_card_receipt_list_response.json (100%) rename {receipt => receiptrepository}/src/test/resources/receipt_list_date_grouping_response.json (100%) create mode 100644 receiptui/.gitignore create mode 100644 receiptui/build.gradle rename {receipt => receiptui}/config/jacoco-settings.gradle (95%) create mode 100644 receiptui/config/lint.xml rename {ui => receiptui}/proguard-rules.pro (100%) rename {receipt => receiptui}/src/androidTest/AndroidManifest.xml (100%) rename {receipt => receiptui}/src/androidTest/java/com/hyperwallet/android/ui/receipt/HyperwalletInstrumentedTestApplication.java (100%) rename {receipt => receiptui}/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java (99%) rename {receipt => receiptui}/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java (99%) rename {receipt => receiptui}/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java (100%) rename {receipt => receiptui}/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java (100%) rename {receipt => receiptui}/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java (100%) rename {receipt => receiptui}/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java (100%) rename {receipt => receiptui}/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java (100%) rename {receipt => receiptui}/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java (100%) rename {receipt => receiptui}/src/main/AndroidManifest.xml (100%) create mode 100644 receiptui/src/main/java/com/hyperwallet/android/ui/receipt/HyperwalletReceiptUi.java rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java (99%) rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java (100%) rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java (99%) rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailActivity.java (100%) rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java (100%) rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptItemDividerDecorator.java (100%) rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java (98%) rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java (97%) rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModel.java (100%) rename {receipt => receiptui}/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java (97%) rename {receipt => receiptui}/src/main/res/drawable/circle_negative.xml (100%) rename {receipt => receiptui}/src/main/res/drawable/circle_positive.xml (100%) rename {receipt => receiptui}/src/main/res/drawable/item_view_border.xml (100%) rename {receipt => receiptui}/src/main/res/drawable/item_view_border_header.xml (100%) rename {receipt => receiptui}/src/main/res/layout/activity_list_prepaid_card_receipt.xml (100%) rename {receipt => receiptui}/src/main/res/layout/activity_list_user_receipt.xml (100%) rename {receipt => receiptui}/src/main/res/layout/activity_receipt_detail.xml (100%) rename {receipt => receiptui}/src/main/res/layout/fragment_list_receipt.xml (100%) rename {receipt => receiptui}/src/main/res/layout/fragment_receipt_detail.xml (100%) rename {receipt => receiptui}/src/main/res/layout/item_receipt.xml (100%) rename {receipt => receiptui}/src/main/res/layout/item_receipt_with_header.xml (100%) rename {receipt => receiptui}/src/main/res/layout/receipt.xml (100%) rename {receipt => receiptui}/src/main/res/values/colors.xml (100%) rename {receipt => receiptui}/src/main/res/values/dimens.xml (100%) rename {receipt => receiptui}/src/main/res/values/strings.xml (100%) rename {receipt => receiptui}/src/main/res/values/styles.xml (100%) rename {receipt => receiptui}/src/main/res/xml/network_security_config.xml (100%) rename {ui/src/androidTest/java/com/hyperwallet/android/ui => receiptui/src/test/java/com/hyperwallet/android/ui/transfermethod}/rule/HyperwalletExternalResourceManager.java (97%) rename {receipt => receiptui}/src/test/resources/authentication_token_response.json (100%) rename {receipt => receiptui}/src/test/resources/prepaid_card_receipt_credit_response.json (100%) rename {receipt => receiptui}/src/test/resources/prepaid_card_receipt_debit_response.json (100%) create mode 100644 receiptui/src/test/resources/prepaid_card_receipt_list_response.json rename {receipt => receiptui}/src/test/resources/prepaid_card_receipt_unknown_type_response.json (100%) rename {receipt => receiptui}/src/test/resources/receipt_credit_response.json (100%) rename {receipt => receiptui}/src/test/resources/receipt_debit_response.json (100%) create mode 100644 receiptui/src/test/resources/receipt_list_date_grouping_response.json rename {receipt => receiptui}/src/test/resources/receipt_list_paged_last_response.json (100%) rename {receipt => receiptui}/src/test/resources/receipt_list_paged_response.json (100%) rename {receipt => receiptui}/src/test/resources/receipt_list_paged_second_response.json (100%) rename {receipt => receiptui}/src/test/resources/receipt_list_paged_third_response.json (100%) rename {receipt => receiptui}/src/test/resources/receipt_list_response.json (100%) rename {receipt => receiptui}/src/test/resources/receipt_unknown_type_response.json (100%) create mode 100644 transfermethodrepository/.gitignore create mode 100644 transfermethodrepository/build.gradle create mode 100644 transfermethodrepository/config/jacoco-settings.gradle create mode 100644 transfermethodrepository/config/lint.xml create mode 100644 transfermethodrepository/proguard-rules.pro create mode 100644 transfermethodrepository/src/main/AndroidManifest.xml rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod}/repository/TransferMethodConfigurationRepository.java (97%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod}/repository/TransferMethodConfigurationRepositoryImpl.java (96%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod}/repository/TransferMethodRepository.java (98%) create mode 100644 transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactory.java rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod}/repository/TransferMethodRepositoryImpl.java (99%) rename {ui/src/test/java/com/hyperwallet/android/ui => transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod}/repository/FieldMapKeyTest.java (94%) rename {ui/src/test/java/com/hyperwallet/android/ui => transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod}/repository/TransferMethodConfigurationRepositoryImplTest.java (98%) rename ui/src/test/java/com/hyperwallet/android/ui/repository/RepositoryFactoryTest.java => transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactoryTest.java (65%) rename {ui/src/test/java/com/hyperwallet/android/ui => transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod}/repository/TransferMethodRepositoryImplTest.java (99%) rename {ui/src/test/java/com/hyperwallet/android/ui => transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod}/rule/HyperwalletExternalResourceManager.java (97%) rename {ui => transfermethodrepository}/src/test/resources/error_tmc_keys_response.json (100%) rename {ui => transfermethodrepository}/src/test/resources/successful_tmc_fields_bank_account_response.json (100%) rename {ui => transfermethodrepository}/src/test/resources/successful_tmc_keys_response.json (100%) rename {ui => transfermethodui}/.gitignore (100%) create mode 100644 transfermethodui/build.gradle rename {ui => transfermethodui}/config/jacoco-settings.gradle (79%) rename {ui => transfermethodui}/config/lint.xml (100%) create mode 100644 transfermethodui/proguard-rules.pro rename {ui => transfermethodui}/src/androidTest/AndroidManifest.xml (62%) rename {ui => transfermethodui}/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java (94%) rename {ui => transfermethodui}/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java (95%) rename {ui => transfermethodui}/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java (93%) rename {ui/src/androidTest/java/com/hyperwallet/android/ui => transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod}/HyperwalletInstrumentedTestApplication.java (93%) rename {ui => transfermethodui}/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java (97%) rename {ui => transfermethodui}/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java (91%) rename {ui => transfermethodui}/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java (94%) create mode 100644 transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java rename {ui/src/androidTest/java/com/hyperwallet/android/ui => transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod}/rule/HyperwalletMockWebServer.java (98%) rename {ui/src/androidTest/java/com/hyperwallet/android/ui => transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod}/util/EspressoUtils.java (99%) rename {ui/src/androidTest/java/com/hyperwallet/android/ui => transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod}/util/NestedScrollToAction.java (95%) rename {ui/src/androidTest/java/com/hyperwallet/android/ui => transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod}/util/RecyclerViewCountAssertion.java (93%) rename {ui/src/androidTest/java/com/hyperwallet/android/ui => transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod}/util/TestAuthenticationProvider.java (96%) rename {ui => transfermethodui}/src/main/AndroidManifest.xml (91%) rename ui/src/main/java/com/hyperwallet/android/ui/HyperwalletLocalBroadcast.java => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodLocalBroadcast.java (86%) rename ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodUi.java (63%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/AddTransferMethodActivity.java (97%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/AddTransferMethodContract.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/AddTransferMethodFragment.java (96%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/AddTransferMethodPresenter.java (95%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/CountrySelectionDialogFragment.java (99%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/CurrencySelectionDialogFragment.java (99%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/FeeFormatter.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/ListTransferMethodActivity.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/ListTransferMethodContract.java (97%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/ListTransferMethodFragment.java (95%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/ListTransferMethodPresenter.java (96%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/OnTransferMethodDeactivateCallback.java (95%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/SelectTransferMethodActivity.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/SelectTransferMethodContract.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/SelectTransferMethodFragment.java (96%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/SelectTransferMethodPresenter.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/ToolbarEventListener.java (95%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/TransferMethodConfirmDeactivationDialogFragment.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/TransferMethodSelectionItem.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui/transfermethod => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view}/TransferMethodUtils.java (99%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/WidgetDateDialogFragment.java (97%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/WidgetSelectionDialogFragment.java (99%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/AbstractWidget.java (99%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/DateChangedListener.java (94%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/DateUtils.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/DateWidget.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/DefaultAccountWidget.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/ExpireDateUtils.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/ExpiryDateWidget.java (95%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/NumberWidget.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/PhoneWidget.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/SelectionWidget.java (97%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/TextWidget.java (98%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/WidgetEventListener.java (96%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/WidgetFactory.java (97%) rename {ui/src/main/java/com/hyperwallet/android/ui => transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod}/view/widget/WidgetInputState.java (98%) rename {ui => transfermethodui}/src/main/res/layout/activity_add_transfer_method.xml (96%) rename {ui => transfermethodui}/src/main/res/layout/activity_list_transfer_method.xml (94%) rename {ui => transfermethodui}/src/main/res/layout/activity_select_transfer_method.xml (98%) rename {ui => transfermethodui}/src/main/res/layout/dialog_fragment_country_selection.xml (100%) rename {ui => transfermethodui}/src/main/res/layout/dialog_fragment_currency_selection.xml (100%) rename {ui => transfermethodui}/src/main/res/layout/dialog_fragment_widget_selection.xml (100%) rename {ui => transfermethodui}/src/main/res/layout/fragment_add_transfer_method.xml (99%) rename {ui => transfermethodui}/src/main/res/layout/fragment_list_transfer_method.xml (96%) rename {ui => transfermethodui}/src/main/res/layout/fragment_select_transfer_method.xml (98%) rename {ui => transfermethodui}/src/main/res/layout/item_country.xml (100%) rename {ui => transfermethodui}/src/main/res/layout/item_currency.xml (100%) rename {ui => transfermethodui}/src/main/res/layout/item_transfer_method_type.xml (100%) rename {ui => transfermethodui}/src/main/res/layout/item_widget_layout.xml (100%) rename {ui => transfermethodui}/src/main/res/layout/item_widget_section_header.xml (100%) rename {ui => transfermethodui}/src/main/res/layout/item_widget_selection.xml (100%) rename {ui => transfermethodui}/src/main/res/menu/menu_country_selection.xml (100%) rename {ui => transfermethodui}/src/main/res/menu/menu_currency_selection.xml (100%) rename {ui => transfermethodui}/src/main/res/menu/menu_widget_selection.xml (100%) rename {ui => transfermethodui}/src/main/res/menu/transfer_method_context_menu.xml (100%) rename {ui => transfermethodui}/src/main/res/mipmap-hdpi/ic_launcher_foreground.png (100%) rename {ui => transfermethodui}/src/main/res/mipmap-mdpi/ic_launcher_foreground.png (100%) rename {ui => transfermethodui}/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png (100%) rename {ui => transfermethodui}/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png (100%) rename {ui => transfermethodui}/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png (100%) rename {ui => transfermethodui}/src/main/res/values/ic_launcher_background.xml (100%) rename {ui => transfermethodui}/src/main/res/values/ids.xml (100%) rename {ui => transfermethodui}/src/main/res/values/strings.xml (100%) rename {ui => transfermethodui}/src/main/res/values/styles.xml (100%) rename {ui => transfermethodui}/src/main/res/xml/network_security_config.xml (100%) rename {ui => transfermethodui}/src/main/res/xml/searchable.xml (100%) rename {ui => transfermethodui}/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java (96%) rename {ui => transfermethodui}/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java (97%) rename {ui => transfermethodui}/src/test/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodPresenterTest.java (98%) rename {ui => transfermethodui}/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java (98%) rename {ui => transfermethodui}/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java (97%) create mode 100644 transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java rename {ui/src/test/java/com/hyperwallet/android/ui => transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod}/view/widget/DateUtilsTest.java (98%) rename {ui/src/test/java/com/hyperwallet/android/ui => transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod}/view/widget/ExpireDateUtilsTest.java (98%) rename {ui => transfermethodui}/src/test/resources/add_transfer_method_presenter_test.json (100%) rename {ui => transfermethodui}/src/test/resources/authentication_token_response.json (100%) rename {ui => transfermethodui}/src/test/resources/bank_account_duplicate_routing_response.json (100%) rename {ui => transfermethodui}/src/test/resources/bank_account_invalid_routing_response.json (100%) rename {ui => transfermethodui}/src/test/resources/bank_account_response.json (100%) rename {ui => transfermethodui}/src/test/resources/bank_card_response.json (100%) rename {ui => transfermethodui}/src/test/resources/common_validation_error_test_diff_min_max.json (100%) rename {ui => transfermethodui}/src/test/resources/common_validation_error_test_same_min_max.json (100%) rename {ui => transfermethodui}/src/test/resources/error_bank_card_response.json (100%) rename {ui => transfermethodui}/src/test/resources/error_tmc_fields_response.json (100%) create mode 100644 transfermethodui/src/test/resources/error_tmc_keys_response.json rename {ui => transfermethodui}/src/test/resources/fee_information.json (100%) rename {ui => transfermethodui}/src/test/resources/invalid_json_response.json (100%) rename {ui => transfermethodui}/src/test/resources/partial_success_tmc_keys_response.json (100%) rename {ui => transfermethodui}/src/test/resources/paypal_invalid_email_response.json (100%) rename {ui => transfermethodui}/src/test/resources/paypal_response.json (100%) create mode 100644 transfermethodui/src/test/resources/successful_tmc_fields_bank_account_response.json rename {ui => transfermethodui}/src/test/resources/successful_tmc_fields_bank_card_response.json (100%) rename {ui => transfermethodui}/src/test/resources/successful_tmc_fields_empty_details_response.json (100%) rename {ui => transfermethodui}/src/test/resources/successful_tmc_fields_paypal_response.json (100%) rename {ui => transfermethodui}/src/test/resources/successful_tmc_keys_empty_fee_response.json (100%) rename {ui => transfermethodui}/src/test/resources/successful_tmc_keys_empty_processing_response.json (100%) rename {ui => transfermethodui}/src/test/resources/successful_tmc_keys_large_response.json (100%) create mode 100644 transfermethodui/src/test/resources/successful_tmc_keys_response.json rename {ui => transfermethodui}/src/test/resources/transfer_method_deactivate_success.json (100%) rename {ui => transfermethodui}/src/test/resources/transfer_method_list_deleted_response.json (100%) rename {ui => transfermethodui}/src/test/resources/transfer_method_list_response.json (100%) rename {ui => transfermethodui}/src/test/resources/transfer_method_list_single_bank_account_response.json (100%) rename {ui => transfermethodui}/src/test/resources/transfer_method_list_single_bank_card_response.json (100%) rename {ui => transfermethodui}/src/test/resources/transfer_method_list_single_paypal_account_response.json (100%) rename {ui => transfermethodui}/src/test/resources/user_business_response.json (100%) rename {ui => transfermethodui}/src/test/resources/user_ca_response.json (100%) rename {ui => transfermethodui}/src/test/resources/user_no_country_response.json (100%) rename {ui => transfermethodui}/src/test/resources/user_not_configured_country_response.json (100%) rename {ui => transfermethodui}/src/test/resources/user_response.json (100%) delete mode 100644 ui/build.gradle delete mode 100644 ui/src/main/java/com/hyperwallet/android/ui/repository/RepositoryFactory.java create mode 100644 userrepository/.gitignore create mode 100644 userrepository/build.gradle create mode 100644 userrepository/config/jacoco-settings.gradle create mode 100644 userrepository/config/lint.xml create mode 100644 userrepository/proguard-rules.pro create mode 100644 userrepository/src/main/AndroidManifest.xml rename {ui/src/main/java/com/hyperwallet/android/ui => userrepository/src/main/java/com/hyperwallet/android/ui/user}/repository/UserRepository.java (97%) create mode 100644 userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepositoryFactory.java rename {ui/src/main/java/com/hyperwallet/android/ui => userrepository/src/main/java/com/hyperwallet/android/ui/user}/repository/UserRepositoryImpl.java (98%) create mode 100644 userrepository/src/test/java/com/hyperwallet/android/ui/user/repository/UserRepositoryFactoryTest.java rename {ui/src/test/java/com/hyperwallet/android/ui => userrepository/src/test/java/com/hyperwallet/android/ui/user}/repository/UserRepositoryImplTest.java (97%) diff --git a/.gitignore b/.gitignore index 54b1252fb..eabbab986 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,9 @@ local.properties *.log # Android Studio captures folder -captures/ \ No newline at end of file +captures/ + + +*.exec + +*.hprof \ No newline at end of file diff --git a/android-library.gradle b/android-library.gradle index 620173287..750c9a8d9 100644 --- a/android-library.gradle +++ b/android-library.gradle @@ -55,9 +55,9 @@ task sourcesJar(type: Jar) { } dependencies { - implementation "com.google.android.material:material:$androidMaterialVersion" - api "com.hyperwallet.android:core-sdk:$hyperwalletCoreVersion" + api "com.hyperwallet.android:core-sdk:$hyperwalletCoreVersion" + implementation "com.google.android.material:material:$androidMaterialVersion" implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion" androidTestImplementation "androidx.test.ext:junit:$extJunitVerson" @@ -66,7 +66,4 @@ dependencies { testImplementation group: 'org.mockito', name: 'mockito-core', version: "$mockitoVersion" testImplementation group: 'pl.pragmatists', name: 'JUnitParams', version: "$junitParamsVersion" -} - - - +} \ No newline at end of file diff --git a/common/.gitignore b/commonrepository/.gitignore similarity index 100% rename from common/.gitignore rename to commonrepository/.gitignore diff --git a/commonrepository/build.gradle b/commonrepository/build.gradle new file mode 100644 index 000000000..2901b2ef0 --- /dev/null +++ b/commonrepository/build.gradle @@ -0,0 +1,7 @@ +apply from: "$rootProject.projectDir/android-library.gradle" +description = 'Hyperwallet Common Repository SDK for Android to integrate with the Hyperwallet Platform' +project.ext { + mavenName = 'Hyperwallet Android Common Repository SDK' +} +apply from: "$rootProject.projectDir/publish.gradle" + diff --git a/commonrepository/config/jacoco-settings.gradle b/commonrepository/config/jacoco-settings.gradle new file mode 100644 index 000000000..fd79c8da1 --- /dev/null +++ b/commonrepository/config/jacoco-settings.gradle @@ -0,0 +1,82 @@ +apply plugin: 'jacoco' + +final def jacocoVersion = "0.8.2" + +jacoco { + toolVersion = jacocoVersion +} + +android { + testOptions { + unitTests { + includeAndroidResources = true + returnDefaultValues = true + } + unitTests.all { + jacoco { + includeNoLocationClasses = true + } + } + } +} + +def fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/common/repository/EspressoIdlingResource.*', + '**/com/hyperwallet/android/ui/common/repository/Event.*' +] + +def debugClassPaths = [ + '**/intermediates/javac/debug/*/classes/**' +] + +final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] + +task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { + + group = 'Reporting' + description = 'Generate Jacoco coverage reports.' + + reports { + html { + enabled = true + destination file("$buildDir/reports/jacoco") + } + } + + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") +} + +task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { + + group = 'Verification' + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") + + violationRules { + setFailOnViolation(true) + + rule { + element = 'CLASS' + limit { + value = 'COVEREDRATIO' + counter = 'BRANCH' + minimum = 0.65 + } + } + } +} + diff --git a/common/config/lint.xml b/commonrepository/config/lint.xml similarity index 100% rename from common/config/lint.xml rename to commonrepository/config/lint.xml diff --git a/common/proguard-rules.pro b/commonrepository/proguard-rules.pro similarity index 100% rename from common/proguard-rules.pro rename to commonrepository/proguard-rules.pro diff --git a/commonrepository/src/main/AndroidManifest.xml b/commonrepository/src/main/AndroidManifest.xml new file mode 100644 index 000000000..ab9a2cf4c --- /dev/null +++ b/commonrepository/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/util/EspressoIdlingResource.java b/commonrepository/src/main/java/com/hyperwallet/android/ui/common/repository/EspressoIdlingResource.java similarity index 91% rename from common/src/main/java/com/hyperwallet/android/ui/common/util/EspressoIdlingResource.java rename to commonrepository/src/main/java/com/hyperwallet/android/ui/common/repository/EspressoIdlingResource.java index 56c870127..dafe63694 100644 --- a/common/src/main/java/com/hyperwallet/android/ui/common/util/EspressoIdlingResource.java +++ b/commonrepository/src/main/java/com/hyperwallet/android/ui/common/repository/EspressoIdlingResource.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.common.util; +package com.hyperwallet.android.ui.common.repository; import androidx.test.espresso.IdlingResource; import androidx.test.espresso.idling.CountingIdlingResource; diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java b/commonrepository/src/main/java/com/hyperwallet/android/ui/common/repository/Event.java similarity index 97% rename from common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java rename to commonrepository/src/main/java/com/hyperwallet/android/ui/common/repository/Event.java index 984bb9995..36e63f1e8 100644 --- a/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/Event.java +++ b/commonrepository/src/main/java/com/hyperwallet/android/ui/common/repository/Event.java @@ -14,7 +14,7 @@ * 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.common.viewmodel; +package com.hyperwallet.android.ui.common.repository; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/receipt/.gitignore b/commonui/.gitignore similarity index 100% rename from receipt/.gitignore rename to commonui/.gitignore diff --git a/commonui/build.gradle b/commonui/build.gradle new file mode 100644 index 000000000..30d929e32 --- /dev/null +++ b/commonui/build.gradle @@ -0,0 +1,10 @@ +apply from: "$rootProject.projectDir/android-library.gradle" +description = 'Hyperwallet Common UI SDK for Android to integrate with the Hyperwallet Platform' +project.ext { + mavenName = 'Hyperwallet Android Common UI SDK' +} +apply from: "$rootProject.projectDir/publish.gradle" + +dependencies { + implementation project(':commonrepository') +} \ No newline at end of file diff --git a/common/config/jacoco-settings.gradle b/commonui/config/jacoco-settings.gradle similarity index 92% rename from common/config/jacoco-settings.gradle rename to commonui/config/jacoco-settings.gradle index 0fe7bbd10..fa8fde9dd 100644 --- a/common/config/jacoco-settings.gradle +++ b/commonui/config/jacoco-settings.gradle @@ -23,9 +23,7 @@ android { def fileFilter = ['**/BuildConfig.*', '**/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.*', '**/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.*', - '**/com/hyperwallet/android/ui/common/view/OneClickListener.*', - '**/com/hyperwallet/android/ui/common/util/EspressoIdlingResource.*', - '**/com/hyperwallet/android/ui/common/viewmodel/Event.*' + '**/com/hyperwallet/android/ui/common/view/OneClickListener.*' ] def debugClassPaths = [ diff --git a/commonui/config/lint.xml b/commonui/config/lint.xml new file mode 100644 index 000000000..3c83d4bb5 --- /dev/null +++ b/commonui/config/lint.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/receipt/proguard-rules.pro b/commonui/proguard-rules.pro similarity index 100% rename from receipt/proguard-rules.pro rename to commonui/proguard-rules.pro diff --git a/common/src/main/AndroidManifest.xml b/commonui/src/main/AndroidManifest.xml similarity index 100% rename from common/src/main/AndroidManifest.xml rename to commonui/src/main/AndroidManifest.xml diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/util/DateUtils.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/util/DateUtils.java similarity index 100% rename from common/src/main/java/com/hyperwallet/android/ui/common/util/DateUtils.java rename to commonui/src/main/java/com/hyperwallet/android/ui/common/util/DateUtils.java diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.java similarity index 100% rename from common/src/main/java/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.java rename to commonui/src/main/java/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.java diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java similarity index 100% rename from common/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java rename to commonui/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.java similarity index 100% rename from common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.java rename to commonui/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.java diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentContract.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentContract.java similarity index 100% rename from common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentContract.java rename to commonui/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentContract.java diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenter.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenter.java similarity index 100% rename from common/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenter.java rename to commonui/src/main/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenter.java diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/view/error/OnNetworkErrorCallback.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/error/OnNetworkErrorCallback.java similarity index 100% rename from common/src/main/java/com/hyperwallet/android/ui/common/view/error/OnNetworkErrorCallback.java rename to commonui/src/main/java/com/hyperwallet/android/ui/common/view/error/OnNetworkErrorCallback.java diff --git a/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java similarity index 94% rename from common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java rename to commonui/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java index b5916f1b2..1d868e791 100644 --- a/common/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java +++ b/commonui/src/main/java/com/hyperwallet/android/ui/common/viewmodel/ListDetailNavigator.java @@ -19,12 +19,12 @@ /** * Detail interface for having a list UI with detail information through navigation */ -public interface ListDetailNavigator { +public interface ListDetailNavigator { /** * Navigate action * * @param e Navigation event */ - void navigate(Event e); + void navigate(T e); } diff --git a/common/src/main/res/drawable/circle.xml b/commonui/src/main/res/drawable/circle.xml similarity index 100% rename from common/src/main/res/drawable/circle.xml rename to commonui/src/main/res/drawable/circle.xml diff --git a/common/src/main/res/drawable/circle_white.xml b/commonui/src/main/res/drawable/circle_white.xml similarity index 100% rename from common/src/main/res/drawable/circle_white.xml rename to commonui/src/main/res/drawable/circle_white.xml diff --git a/common/src/main/res/drawable/content_border_bottom.xml b/commonui/src/main/res/drawable/content_border_bottom.xml similarity index 100% rename from common/src/main/res/drawable/content_border_bottom.xml rename to commonui/src/main/res/drawable/content_border_bottom.xml diff --git a/common/src/main/res/drawable/content_border_top_bottom.xml b/commonui/src/main/res/drawable/content_border_top_bottom.xml similarity index 100% rename from common/src/main/res/drawable/content_border_top_bottom.xml rename to commonui/src/main/res/drawable/content_border_top_bottom.xml diff --git a/common/src/main/res/drawable/horizontal_divider.xml b/commonui/src/main/res/drawable/horizontal_divider.xml similarity index 100% rename from common/src/main/res/drawable/horizontal_divider.xml rename to commonui/src/main/res/drawable/horizontal_divider.xml diff --git a/common/src/main/res/drawable/ic_baseline_bug_report_24px.xml b/commonui/src/main/res/drawable/ic_baseline_bug_report_24px.xml similarity index 100% rename from common/src/main/res/drawable/ic_baseline_bug_report_24px.xml rename to commonui/src/main/res/drawable/ic_baseline_bug_report_24px.xml diff --git a/common/src/main/res/drawable/ic_baseline_cloud_off_24px.xml b/commonui/src/main/res/drawable/ic_baseline_cloud_off_24px.xml similarity index 100% rename from common/src/main/res/drawable/ic_baseline_cloud_off_24px.xml rename to commonui/src/main/res/drawable/ic_baseline_cloud_off_24px.xml diff --git a/common/src/main/res/drawable/ic_baseline_warning_24px.xml b/commonui/src/main/res/drawable/ic_baseline_warning_24px.xml similarity index 100% rename from common/src/main/res/drawable/ic_baseline_warning_24px.xml rename to commonui/src/main/res/drawable/ic_baseline_warning_24px.xml diff --git a/common/src/main/res/drawable/ic_check_14dp.xml b/commonui/src/main/res/drawable/ic_check_14dp.xml similarity index 100% rename from common/src/main/res/drawable/ic_check_14dp.xml rename to commonui/src/main/res/drawable/ic_check_14dp.xml diff --git a/common/src/main/res/drawable/ic_close_14dp.xml b/commonui/src/main/res/drawable/ic_close_14dp.xml similarity index 100% rename from common/src/main/res/drawable/ic_close_14dp.xml rename to commonui/src/main/res/drawable/ic_close_14dp.xml diff --git a/common/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml b/commonui/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml similarity index 100% rename from common/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml rename to commonui/src/main/res/drawable/ic_keyboard_arrow_down_12dp.xml diff --git a/common/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml b/commonui/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml similarity index 100% rename from common/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml rename to commonui/src/main/res/drawable/ic_keyboard_arrow_left_12dp.xml diff --git a/common/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml b/commonui/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml similarity index 100% rename from common/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml rename to commonui/src/main/res/drawable/ic_keyboard_arrow_right_12dp.xml diff --git a/common/src/main/res/drawable/ic_launcher_background.xml b/commonui/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from common/src/main/res/drawable/ic_launcher_background.xml rename to commonui/src/main/res/drawable/ic_launcher_background.xml diff --git a/common/src/main/res/drawable/ic_placeholder_24dp.xml b/commonui/src/main/res/drawable/ic_placeholder_24dp.xml similarity index 100% rename from common/src/main/res/drawable/ic_placeholder_24dp.xml rename to commonui/src/main/res/drawable/ic_placeholder_24dp.xml diff --git a/common/src/main/res/drawable/ic_search_24dp.xml b/commonui/src/main/res/drawable/ic_search_24dp.xml similarity index 100% rename from common/src/main/res/drawable/ic_search_24dp.xml rename to commonui/src/main/res/drawable/ic_search_24dp.xml diff --git a/common/src/main/res/drawable/ic_three_dots_16dp.xml b/commonui/src/main/res/drawable/ic_three_dots_16dp.xml similarity index 100% rename from common/src/main/res/drawable/ic_three_dots_16dp.xml rename to commonui/src/main/res/drawable/ic_three_dots_16dp.xml diff --git a/common/src/main/res/drawable/ic_trash.xml b/commonui/src/main/res/drawable/ic_trash.xml similarity index 100% rename from common/src/main/res/drawable/ic_trash.xml rename to commonui/src/main/res/drawable/ic_trash.xml diff --git a/common/src/main/res/drawable/oval.xml b/commonui/src/main/res/drawable/oval.xml similarity index 100% rename from common/src/main/res/drawable/oval.xml rename to commonui/src/main/res/drawable/oval.xml diff --git a/common/src/main/res/drawable/view_border_top_bottom.xml b/commonui/src/main/res/drawable/view_border_top_bottom.xml similarity index 100% rename from common/src/main/res/drawable/view_border_top_bottom.xml rename to commonui/src/main/res/drawable/view_border_top_bottom.xml diff --git a/common/src/main/res/drawable/view_item_ripple.xml b/commonui/src/main/res/drawable/view_item_ripple.xml similarity index 100% rename from common/src/main/res/drawable/view_item_ripple.xml rename to commonui/src/main/res/drawable/view_item_ripple.xml diff --git a/common/src/main/res/font/icomoon.ttf b/commonui/src/main/res/font/icomoon.ttf similarity index 100% rename from common/src/main/res/font/icomoon.ttf rename to commonui/src/main/res/font/icomoon.ttf diff --git a/common/src/main/res/values/colors.xml b/commonui/src/main/res/values/colors.xml similarity index 100% rename from common/src/main/res/values/colors.xml rename to commonui/src/main/res/values/colors.xml diff --git a/common/src/main/res/values/dimens.xml b/commonui/src/main/res/values/dimens.xml similarity index 100% rename from common/src/main/res/values/dimens.xml rename to commonui/src/main/res/values/dimens.xml diff --git a/common/src/main/res/values/strings.xml b/commonui/src/main/res/values/strings.xml similarity index 100% rename from common/src/main/res/values/strings.xml rename to commonui/src/main/res/values/strings.xml diff --git a/common/src/main/res/values/styles.xml b/commonui/src/main/res/values/styles.xml similarity index 100% rename from common/src/main/res/values/styles.xml rename to commonui/src/main/res/values/styles.xml diff --git a/common/src/test/java/com/hyperwallet/android/ui/common/util/DateUtilsTest.java b/commonui/src/test/java/com/hyperwallet/android/ui/common/util/DateUtilsTest.java similarity index 100% rename from common/src/test/java/com/hyperwallet/android/ui/common/util/DateUtilsTest.java rename to commonui/src/test/java/com/hyperwallet/android/ui/common/util/DateUtilsTest.java diff --git a/common/src/test/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenterTest.java b/commonui/src/test/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenterTest.java similarity index 100% rename from common/src/test/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenterTest.java rename to commonui/src/test/java/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragmentPresenterTest.java diff --git a/common/build.gradle b/publish.gradle similarity index 79% rename from common/build.gradle rename to publish.gradle index cf60c3f49..8b2f85e97 100644 --- a/common/build.gradle +++ b/publish.gradle @@ -1,7 +1,4 @@ -apply from: "$rootProject.projectDir/android-library.gradle" - - -def aarFile = file("$buildDir/outputs/aar/common-$version" + ".aar") +def aarFile = file("$buildDir/outputs/aar/$project.name-$version" + ".aar") def aarArtifact = artifacts.add('archives', aarFile) { type 'aar' } @@ -23,9 +20,10 @@ publishing { } publications { - hyperwalletCommonUi(MavenPublication) { + hyperwalletUiPublish(MavenPublication) { groupId = hyperwalletGroupId - artifactId = 'common' + artifactId = project.name + version = version artifact(sourcesJar) @@ -33,14 +31,18 @@ publishing { artifact(aarArtifact) pom { - name = 'Hyperwallet Android Common UI SDK' - description = 'Hyperwallet Common UI SDK for Android to integrate with Hyperwallet Platform' + name = project.mavenName + description = project.description url = 'https://github.com/hyperwallet/hyperwallet-android-ui-sdk' pom.withXml { def dependenciesNode = asNode().appendNode('dependencies') configurations.implementation.allDependencies.each { def dependencyNode = dependenciesNode.appendNode('dependency') - dependencyNode.appendNode('groupId', it.group) + if (it.group == "hyperwallet-android-ui-sdk") { + dependencyNode.appendNode('groupId', "com.hyperwallet.android.ui") + } else { + dependencyNode.appendNode('groupId', it.group) + } dependencyNode.appendNode('artifactId', it.name) dependencyNode.appendNode('version', it.version) } @@ -74,7 +76,7 @@ tasks.withType(Sign) { } signing { - sign publishing.publications.hyperwalletCommonUi + sign publishing.publications.hyperwalletUiPublish } sonarqube { @@ -83,6 +85,6 @@ sonarqube { property "sonar.sources", "src/main/java" property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android/ui" property "sonar.libraries", libraries - property "sonar.projectName", "android-ui-sdk-common" + property "sonar.projectName", "android-ui-sdk-$project.name" } } \ No newline at end of file diff --git a/receipt/build.gradle b/receipt/build.gradle deleted file mode 100644 index cff209c86..000000000 --- a/receipt/build.gradle +++ /dev/null @@ -1,111 +0,0 @@ -apply from: "$rootProject.projectDir/android-library.gradle" - -dependencies { - api project(":common") - - implementation "com.google.android.material:material:$androidMaterialVersion" - implementation "androidx.constraintlayout:constraintlayout:$constraintlayoutVersion" - implementation "androidx.legacy:legacy-support-v4:$legacySupportV4Version" - implementation "androidx.recyclerview:recyclerview:$recycleViewVersion" - implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion" - implementation "androidx.paging:paging-runtime:$pagingRuntimeVersion" - - testImplementation "org.robolectric:robolectric:$robolectricVersion" - - androidTestImplementation "androidx.test:rules:$testRulesVersion" - androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" - androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" - androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockServerVersion" - androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanaryVersion" - androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:$leakcanaryVersion" -} - -def aarFile = file("$buildDir/outputs/aar/receipt-$version" + ".aar") -def aarArtifact = artifacts.add('archives', aarFile) { - type 'aar' -} - -def isReleaseVersion = !version.endsWith('SNAPSHOT') - -publishing { - - repositories { - maven { - def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2" - def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots" - url = isReleaseVersion ? releasesRepoUrl : snapshotsRepoUrl - credentials { - username sonatypeUsername - password sonatypePassword - } - } - } - - publications { - hyperwalletReceiptUi(MavenPublication) { - groupId = hyperwalletGroupId - artifactId = 'receipt' - version = version - - artifact(sourcesJar) - artifact(javadocsJar) - artifact(aarArtifact) - - pom { - name = 'Hyperwallet Android Receipt UI SDK' - description = 'Hyperwallet Receipt UI SDK for Android to integrate with Hyperwallet Platform' - url = 'https://github.com/hyperwallet/hyperwallet-android-ui-sdk' - pom.withXml { - def dependenciesNode = asNode().appendNode('dependencies') - configurations.implementation.allDependencies.each { - def dependencyNode = dependenciesNode.appendNode('dependency') - if (it.group == "hyperwallet-android-ui-sdk") { - dependencyNode.appendNode('groupId', "com.hyperwallet.android.ui") - } else { - dependencyNode.appendNode('groupId', it.group) - } - dependencyNode.appendNode('artifactId', it.name) - dependencyNode.appendNode('version', it.version) - } - } - licenses { - license { - name = 'MIT License' - url = 'http://www.opensource.org/licenses/MIT' - } - } - developers { - developer { - id = 'devs' - name = 'Hyperwallet Developers' - } - } - scm { - connection = 'scm:git:git://github.com/hyperwallet/hyperwallet-android-ui-sdk.git' - developerConnection = 'scm:git:git://github.com/hyperwallet/hyperwallet-android-ui-sdk.git' - url = 'https://github.com/hyperwallet/hyperwallet-android-ui-sdk' - } - } - } - } -} - -tasks.withType(Sign) { - onlyIf { - isReleaseVersion && sonatypeUsername?.trim() && sonatypePassword?.trim() - } -} - -signing { - sign publishing.publications.hyperwalletReceiptUi -} - -sonarqube { - properties { - def libraries = project.android.sdkDirectory.getPath() + "/platforms/android-28/android.jar" - property "sonar.sources", "src/main/java" - property "sonar.binaries", "build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/hyperwallet/android/ui" - property "sonar.libraries", libraries - property "sonar.projectName", "android-ui-sdk-receipt" - } -} diff --git a/receiptrepository/.gitignore b/receiptrepository/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/receiptrepository/.gitignore @@ -0,0 +1 @@ +/build diff --git a/receiptrepository/build.gradle b/receiptrepository/build.gradle new file mode 100644 index 000000000..f5390c2fe --- /dev/null +++ b/receiptrepository/build.gradle @@ -0,0 +1,16 @@ +apply from: "$rootProject.projectDir/android-library.gradle" +description = 'Hyperwallet Receipt Repository SDK for Android to integrate with the Hyperwallet Platform' +project.ext { + mavenName = 'Hyperwallet Android Receipt Repository SDK' +} +apply from: "$rootProject.projectDir/publish.gradle" + + +dependencies { + + implementation "androidx.legacy:legacy-support-v4:$legacySupportV4Version" + implementation "androidx.paging:paging-runtime:$pagingRuntimeVersion" + api project(':commonrepository') + + testImplementation "org.robolectric:robolectric:$robolectricVersion" +} \ No newline at end of file diff --git a/receiptrepository/config/jacoco-settings.gradle b/receiptrepository/config/jacoco-settings.gradle new file mode 100644 index 000000000..bb4ffa228 --- /dev/null +++ b/receiptrepository/config/jacoco-settings.gradle @@ -0,0 +1,79 @@ +apply plugin: 'jacoco' + +final def jacocoVersion = "0.8.2" + +jacoco { + toolVersion = jacocoVersion +} + +android { + testOptions { + unitTests { + includeAndroidResources = true + returnDefaultValues = true + } + unitTests.all { + jacoco { + includeNoLocationClasses = true + } + } + } +} + +def fileFilter = ['**/BuildConfig.*' +] + +def debugClassPaths = [ + '**/intermediates/javac/debug/*/classes/**' +] + +final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] + +task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { + + group = 'Reporting' + description = 'Generate Jacoco coverage reports.' + reports { + html { + enabled = true + destination file("$project.buildDir/reports/jacoco") + } + } + + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") +} + +task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { + + group = 'Verification' + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") + + violationRules { + setFailOnViolation(true) + + rule { + element = 'CLASS' + limit { + value = 'COVEREDRATIO' + counter = 'BRANCH' + minimum = 0.65 + } + } + } +} + diff --git a/receipt/config/lint.xml b/receiptrepository/config/lint.xml similarity index 100% rename from receipt/config/lint.xml rename to receiptrepository/config/lint.xml diff --git a/receiptrepository/src/main/AndroidManifest.xml b/receiptrepository/src/main/AndroidManifest.xml new file mode 100644 index 000000000..25d33e545 --- /dev/null +++ b/receiptrepository/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java similarity index 98% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java rename to receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java index 39135cf44..21cd26073 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java +++ b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSource.java @@ -32,8 +32,8 @@ import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.model.receipt.ReceiptQueryParam; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.common.repository.Event; import com.hyperwallet.android.util.DateUtil; import java.util.Calendar; diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactory.java b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactory.java similarity index 100% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactory.java rename to receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactory.java diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java similarity index 97% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java rename to receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java index 021cadcc7..273368fd5 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java +++ b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepository.java @@ -21,7 +21,8 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.Event; + public interface PrepaidCardReceiptRepository { diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java similarity index 97% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java rename to receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java index 4b5fed137..ae7372e1b 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java +++ b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImpl.java @@ -7,7 +7,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.Event; public class PrepaidCardReceiptRepositoryImpl implements PrepaidCardReceiptRepository { diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java similarity index 98% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java rename to receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java index 28e8ef727..e75769bfa 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java +++ b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSource.java @@ -31,8 +31,8 @@ import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.model.receipt.ReceiptQueryParam; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.common.repository.Event; import java.util.Calendar; @@ -117,7 +117,7 @@ public void loadBefore(@NonNull final LoadParams params, /** * @see PageKeyedDataSource#loadAfter(LoadParams, LoadCallback) - * */ + */ @Override public void loadAfter(@NonNull final LoadParams params, final @NonNull LoadCallback callback) { @@ -168,7 +168,7 @@ public Handler getHandler() { /** * Facilitates retry when network is down; any error that we can have a retry operation - * */ + */ void retry() { if (mLoadInitialCallback != null) { loadInitial(mLoadInitialParams, mLoadInitialCallback); @@ -181,7 +181,7 @@ void retry() { * Retrieve reference of Hyperwallet errors inorder for consumers to observe on data changes * * @return Live event data of {@link HyperwalletErrors} - * */ + */ public LiveData> getErrors() { return mErrors; } diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactory.java b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactory.java similarity index 100% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactory.java rename to receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactory.java diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java similarity index 97% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java rename to receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java index 7c72ab664..14a685c39 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java +++ b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepository.java @@ -21,7 +21,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.Event; /** * Receipt Repository Contract diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java similarity index 97% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java rename to receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java index 07a8fbdb9..74a28295b 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java +++ b/receiptrepository/src/main/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImpl.java @@ -22,7 +22,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.Event; /** * {@link UserReceiptRepository} implementation @@ -72,7 +72,7 @@ public LiveData isLoading() { /** * @see UserReceiptRepository#getErrors() - * */ + */ @Override public LiveData> getErrors() { if (mErrorsLiveData == null) { @@ -83,7 +83,7 @@ public LiveData> getErrors() { /** * @see UserReceiptRepository#retryLoadReceipt() - * */ + */ @Override public void retryLoadReceipt() { if (mReceiptDataSourceLiveData.getValue() != null) { diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactoryTest.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactoryTest.java similarity index 100% rename from receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactoryTest.java rename to receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceFactoryTest.java diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java similarity index 99% rename from receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java rename to receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java index e9cf99b89..fd468bfab 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java +++ b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java @@ -29,11 +29,10 @@ import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.model.receipt.ReceiptQueryParam; -import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.util.DateUtil; import org.hamcrest.Matchers; -import org.json.JSONException; import org.json.JSONObject; import org.junit.Before; import org.junit.Rule; @@ -56,20 +55,19 @@ @RunWith(RobolectricTestRunner.class) public class PrepaidCardReceiptDataSourceTest { + // can't be mocked due to params.key is of type Integer and autoboxing will not work with null to 0 + private final PageKeyedDataSource.LoadParams mLoadAfterParams = new PageKeyedDataSource.LoadParams<>( + new Date(), 10); @Rule public MockitoRule mMockito = MockitoJUnit.rule(); @Rule public HyperwalletExternalResourceManager mExternalResourceManager = new HyperwalletExternalResourceManager(); - @Mock private Hyperwallet mHyperwallet; @Mock private PageKeyedDataSource.LoadInitialParams mInitialParams; @Mock private PageKeyedDataSource.LoadInitialCallback mInitialCallback; - // can't be mocked due to params.key is of type Integer and autoboxing will not work with null to 0 - private final PageKeyedDataSource.LoadParams mLoadAfterParams = new PageKeyedDataSource.LoadParams<>( - new Date(), 10); @Mock private PageKeyedDataSource.LoadCallback mLoadAfterCallback; diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java similarity index 97% rename from receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java rename to receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java index 247031513..912741fc0 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java +++ b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptRepositoryImplTest.java @@ -11,7 +11,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.Event; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactoryTest.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactoryTest.java similarity index 100% rename from receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactoryTest.java rename to receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceFactoryTest.java diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java similarity index 99% rename from receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java rename to receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java index e61646e32..a26ed1b15 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java +++ b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java @@ -27,7 +27,7 @@ import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.model.receipt.ReceiptQueryParam; -import com.hyperwallet.android.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; import org.hamcrest.Matchers; import org.json.JSONObject; @@ -52,20 +52,19 @@ @RunWith(RobolectricTestRunner.class) public class UserReceiptDataSourceTest { + // can't be mocked due to params.key is of type Integer and autoboxing will not work with null to 0 + private final PageKeyedDataSource.LoadParams mLoadAfterParams = + new PageKeyedDataSource.LoadParams<>(10, 10); @Rule public MockitoRule mMockito = MockitoJUnit.rule(); @Rule public HyperwalletExternalResourceManager mExternalResourceManager = new HyperwalletExternalResourceManager(); - @Mock private Hyperwallet mHyperwallet; @Mock private PageKeyedDataSource.LoadInitialParams mInitialParams; @Mock private PageKeyedDataSource.LoadInitialCallback mInitialCallback; - // can't be mocked due to params.key is of type Integer and autoboxing will not work with null to 0 - private final PageKeyedDataSource.LoadParams mLoadAfterParams = - new PageKeyedDataSource.LoadParams<>(10, 10); @Mock private PageKeyedDataSource.LoadCallback mLoadAfterCallback; diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java similarity index 97% rename from receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java rename to receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java index 5b3005bda..74be4edac 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java +++ b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptRepositoryImplTest.java @@ -11,7 +11,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.Event; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/receipt/src/test/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java similarity index 98% rename from receipt/src/test/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java rename to receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java index 9061af9b8..abc9bf5da 100644 --- a/receipt/src/test/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java +++ b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.rule; +package com.hyperwallet.android.ui.receipt.rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; diff --git a/receipt/src/test/resources/prepaid_card_receipt_list_response.json b/receiptrepository/src/test/resources/prepaid_card_receipt_list_response.json similarity index 100% rename from receipt/src/test/resources/prepaid_card_receipt_list_response.json rename to receiptrepository/src/test/resources/prepaid_card_receipt_list_response.json diff --git a/receipt/src/test/resources/receipt_list_date_grouping_response.json b/receiptrepository/src/test/resources/receipt_list_date_grouping_response.json similarity index 100% rename from receipt/src/test/resources/receipt_list_date_grouping_response.json rename to receiptrepository/src/test/resources/receipt_list_date_grouping_response.json diff --git a/receiptui/.gitignore b/receiptui/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/receiptui/.gitignore @@ -0,0 +1 @@ +/build diff --git a/receiptui/build.gradle b/receiptui/build.gradle new file mode 100644 index 000000000..081d29e7f --- /dev/null +++ b/receiptui/build.gradle @@ -0,0 +1,25 @@ +apply from: "$rootProject.projectDir/android-library.gradle" +description = 'Hyperwallet Receipt UI SDK for Android to integrate with the Hyperwallet Platform' +project.ext { + mavenName = 'Hyperwallet Android Receipt UI SDK' +} +apply from: "$rootProject.projectDir/publish.gradle" + +dependencies { + implementation project(':commonui') + implementation project(":receiptrepository") + + implementation "com.google.android.material:material:$androidMaterialVersion" + implementation "androidx.constraintlayout:constraintlayout:$constraintlayoutVersion" + implementation "androidx.legacy:legacy-support-v4:$legacySupportV4Version" + implementation "androidx.recyclerview:recyclerview:$recycleViewVersion" + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion" + implementation "androidx.paging:paging-runtime:$pagingRuntimeVersion" + + androidTestImplementation "androidx.test:rules:$testRulesVersion" + androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" + androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" + androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockServerVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanaryVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:$leakcanaryVersion" +} diff --git a/receipt/config/jacoco-settings.gradle b/receiptui/config/jacoco-settings.gradle similarity index 95% rename from receipt/config/jacoco-settings.gradle rename to receiptui/config/jacoco-settings.gradle index e0bb22486..7dbc462e6 100644 --- a/receipt/config/jacoco-settings.gradle +++ b/receiptui/config/jacoco-settings.gradle @@ -22,8 +22,7 @@ android { def fileFilter = ['**/BuildConfig.*', '**/com/hyperwallet/android/ui/receipt/view/*.*', - '**/com/hyperwallet/android/ui/receipt/viewmodel/*.*', - '**/com/hyperwallet/android/ui/receipt/repository/ReceiptRepositoryImpl.*' + '**/com/hyperwallet/android/ui/receipt/viewmodel/*.*' ] def debugClassPaths = [ diff --git a/receiptui/config/lint.xml b/receiptui/config/lint.xml new file mode 100644 index 000000000..ff446fa9e --- /dev/null +++ b/receiptui/config/lint.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/ui/proguard-rules.pro b/receiptui/proguard-rules.pro similarity index 100% rename from ui/proguard-rules.pro rename to receiptui/proguard-rules.pro diff --git a/receipt/src/androidTest/AndroidManifest.xml b/receiptui/src/androidTest/AndroidManifest.xml similarity index 100% rename from receipt/src/androidTest/AndroidManifest.xml rename to receiptui/src/androidTest/AndroidManifest.xml diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/HyperwalletInstrumentedTestApplication.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/HyperwalletInstrumentedTestApplication.java similarity index 100% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/HyperwalletInstrumentedTestApplication.java rename to receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/HyperwalletInstrumentedTestApplication.java diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java similarity index 99% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java rename to receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java index 2e9c9ff14..910d69628 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java +++ b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java @@ -41,8 +41,8 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; import com.hyperwallet.android.ui.common.util.DateUtils; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.receipt.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.receipt.util.RecyclerViewCountAssertion; @@ -319,8 +319,8 @@ public void testListPrepaidCardReceipt_checkDateTextOnLocaleChange() { @Test public void testListPrepaidCardReceipt_displaysNetworkErrorDialogOnConnectionTimeout() { mMockWebServer.getServer().enqueue(new MockResponse().setResponseCode(HTTP_OK).setBody(sResourceManager - .getResourceContent("prepaid_card_receipt_debit_response.json")).throttleBody(512, 10, - TimeUnit.SECONDS)); + .getResourceContent("prepaid_card_receipt_debit_response.json")).setBodyDelay(10500, + TimeUnit.MILLISECONDS)); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("prepaid_card_receipt_debit_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java similarity index 99% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java rename to receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java index 0bb97d2ff..37809b494 100644 --- a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java +++ b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java @@ -39,8 +39,8 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; import com.hyperwallet.android.ui.common.util.DateUtils; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.receipt.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.receipt.util.RecyclerViewCountAssertion; @@ -417,7 +417,7 @@ public void testListReceipt_checkDateTextOnLocaleChange() { @Test public void testListReceipt_displaysNetworkErrorDialogOnConnectionTimeout() { mMockWebServer.getServer().enqueue(new MockResponse().setResponseCode(HTTP_OK).setBody(sResourceManager - .getResourceContent("receipt_debit_response.json")).throttleBody(512, 10, TimeUnit.SECONDS)); + .getResourceContent("receipt_debit_response.json")).setBodyDelay(10500, TimeUnit.MILLISECONDS)); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager .getResourceContent("receipt_debit_response.json")).mock(); mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java similarity index 100% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java rename to receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java similarity index 100% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java rename to receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java similarity index 100% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java rename to receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java similarity index 100% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java rename to receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java similarity index 100% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java rename to receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java diff --git a/receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java similarity index 100% rename from receipt/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java rename to receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java diff --git a/receipt/src/main/AndroidManifest.xml b/receiptui/src/main/AndroidManifest.xml similarity index 100% rename from receipt/src/main/AndroidManifest.xml rename to receiptui/src/main/AndroidManifest.xml diff --git a/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/HyperwalletReceiptUi.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/HyperwalletReceiptUi.java new file mode 100644 index 000000000..4b3fdd550 --- /dev/null +++ b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/HyperwalletReceiptUi.java @@ -0,0 +1,68 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Hyperwallet Systems Inc. + * + * 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 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.receipt; + +import android.content.Context; +import android.content.Intent; + +import androidx.annotation.NonNull; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; +import com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity; +import com.hyperwallet.android.ui.receipt.view.ListUserReceiptActivity; + +public final class HyperwalletReceiptUi { + + private static HyperwalletReceiptUi sInstance; + + private HyperwalletReceiptUi() { + } + + /** + * @param authenticationTokenProvider An implementation of the {@link HyperwalletAuthenticationTokenProvider} + * @return Returns a newly created HyperwalletTransferMethodUi that can be used to get Intents to launch different + * activities. + */ + public static synchronized HyperwalletReceiptUi getInstance( + @NonNull final HyperwalletAuthenticationTokenProvider authenticationTokenProvider) { + if (sInstance == null) { + sInstance = new HyperwalletReceiptUi(); + Hyperwallet.getInstance(authenticationTokenProvider); + } + return sInstance; + } + + /** + * @param context A Context of the application consuming this Intent. + * @return an Intent with the data necessary to launch the {@link ListUserReceiptActivity} + */ + public Intent getIntentListUserReceiptActivity(@NonNull final Context context) { + return new Intent(context, ListUserReceiptActivity.class); + } + + /** + * @param context A Context of the application consuming this Intent. + * @return an Intent with the data necessary to launch the {@link ListPrepaidCardReceiptActivity} + */ + public Intent getIntentListPrepaidCardReceiptActivity(@NonNull final Context context, @NonNull final String token) { + Intent intent = new Intent(context, ListPrepaidCardReceiptActivity.class); + intent.putExtra(ListPrepaidCardReceiptActivity.EXTRA_PREPAID_CARD_TOKEN, token); + return intent; + } + +} diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java similarity index 99% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java index b774436d4..e5ef5a937 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java +++ b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ListPrepaidCardReceiptActivity.java @@ -33,9 +33,9 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.repository.Event; import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; -import com.hyperwallet.android.ui.common.viewmodel.Event; import com.hyperwallet.android.ui.common.viewmodel.ListDetailNavigator; import com.hyperwallet.android.ui.receipt.R; import com.hyperwallet.android.ui.receipt.repository.PrepaidCardReceiptRepositoryImpl; diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java similarity index 100% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ListReceiptFragment.java diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java similarity index 99% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java index bc66e9609..4b56bfa30 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java +++ b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ListUserReceiptActivity.java @@ -33,9 +33,9 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.common.repository.Event; import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; -import com.hyperwallet.android.ui.common.viewmodel.Event; import com.hyperwallet.android.ui.common.viewmodel.ListDetailNavigator; import com.hyperwallet.android.ui.receipt.R; import com.hyperwallet.android.ui.receipt.repository.UserReceiptRepositoryImpl; diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailActivity.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailActivity.java similarity index 100% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailActivity.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailActivity.java diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java similarity index 100% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptDetailFragment.java diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptItemDividerDecorator.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptItemDividerDecorator.java similarity index 100% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptItemDividerDecorator.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/view/ReceiptItemDividerDecorator.java diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java similarity index 98% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java index 73f697bca..0b72276be 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java +++ b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java @@ -26,7 +26,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.Event; import com.hyperwallet.android.ui.receipt.repository.PrepaidCardReceiptRepository; public class ListPrepaidCardReceiptViewModel extends ReceiptViewModel { diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java similarity index 97% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java index 9b9b63b2c..fcb308629 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java +++ b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModel.java @@ -26,7 +26,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.Event; import com.hyperwallet.android.ui.receipt.repository.UserReceiptRepository; public class ListUserReceiptViewModel extends ReceiptViewModel { @@ -74,28 +74,28 @@ public LiveData> getReceiptList() { /** * @see ReceiptViewModel#retryLoadReceipts() - * */ + */ public void retryLoadReceipts() { mUserReceiptRepository.retryLoadReceipt(); } /** * @see ReceiptViewModel#getDetailNavigation() - * */ + */ public LiveData> getDetailNavigation() { return mDetailNavigation; } /** * @see ReceiptViewModel#setDetailNavigation(Receipt) - * */ + */ public void setDetailNavigation(@NonNull final Receipt receipt) { mDetailNavigation.postValue(new Event<>(receipt)); } /** * @see ViewModel#onCleared() - * */ + */ @Override protected void onCleared() { super.onCleared(); diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModel.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModel.java similarity index 100% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModel.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModel.java diff --git a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java similarity index 97% rename from receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java rename to receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java index f100b86bc..9cb878969 100644 --- a/receipt/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java +++ b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptViewModel.java @@ -23,7 +23,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.common.viewmodel.Event; +import com.hyperwallet.android.ui.common.repository.Event; public abstract class ReceiptViewModel extends ViewModel { diff --git a/receipt/src/main/res/drawable/circle_negative.xml b/receiptui/src/main/res/drawable/circle_negative.xml similarity index 100% rename from receipt/src/main/res/drawable/circle_negative.xml rename to receiptui/src/main/res/drawable/circle_negative.xml diff --git a/receipt/src/main/res/drawable/circle_positive.xml b/receiptui/src/main/res/drawable/circle_positive.xml similarity index 100% rename from receipt/src/main/res/drawable/circle_positive.xml rename to receiptui/src/main/res/drawable/circle_positive.xml diff --git a/receipt/src/main/res/drawable/item_view_border.xml b/receiptui/src/main/res/drawable/item_view_border.xml similarity index 100% rename from receipt/src/main/res/drawable/item_view_border.xml rename to receiptui/src/main/res/drawable/item_view_border.xml diff --git a/receipt/src/main/res/drawable/item_view_border_header.xml b/receiptui/src/main/res/drawable/item_view_border_header.xml similarity index 100% rename from receipt/src/main/res/drawable/item_view_border_header.xml rename to receiptui/src/main/res/drawable/item_view_border_header.xml diff --git a/receipt/src/main/res/layout/activity_list_prepaid_card_receipt.xml b/receiptui/src/main/res/layout/activity_list_prepaid_card_receipt.xml similarity index 100% rename from receipt/src/main/res/layout/activity_list_prepaid_card_receipt.xml rename to receiptui/src/main/res/layout/activity_list_prepaid_card_receipt.xml diff --git a/receipt/src/main/res/layout/activity_list_user_receipt.xml b/receiptui/src/main/res/layout/activity_list_user_receipt.xml similarity index 100% rename from receipt/src/main/res/layout/activity_list_user_receipt.xml rename to receiptui/src/main/res/layout/activity_list_user_receipt.xml diff --git a/receipt/src/main/res/layout/activity_receipt_detail.xml b/receiptui/src/main/res/layout/activity_receipt_detail.xml similarity index 100% rename from receipt/src/main/res/layout/activity_receipt_detail.xml rename to receiptui/src/main/res/layout/activity_receipt_detail.xml diff --git a/receipt/src/main/res/layout/fragment_list_receipt.xml b/receiptui/src/main/res/layout/fragment_list_receipt.xml similarity index 100% rename from receipt/src/main/res/layout/fragment_list_receipt.xml rename to receiptui/src/main/res/layout/fragment_list_receipt.xml diff --git a/receipt/src/main/res/layout/fragment_receipt_detail.xml b/receiptui/src/main/res/layout/fragment_receipt_detail.xml similarity index 100% rename from receipt/src/main/res/layout/fragment_receipt_detail.xml rename to receiptui/src/main/res/layout/fragment_receipt_detail.xml diff --git a/receipt/src/main/res/layout/item_receipt.xml b/receiptui/src/main/res/layout/item_receipt.xml similarity index 100% rename from receipt/src/main/res/layout/item_receipt.xml rename to receiptui/src/main/res/layout/item_receipt.xml diff --git a/receipt/src/main/res/layout/item_receipt_with_header.xml b/receiptui/src/main/res/layout/item_receipt_with_header.xml similarity index 100% rename from receipt/src/main/res/layout/item_receipt_with_header.xml rename to receiptui/src/main/res/layout/item_receipt_with_header.xml diff --git a/receipt/src/main/res/layout/receipt.xml b/receiptui/src/main/res/layout/receipt.xml similarity index 100% rename from receipt/src/main/res/layout/receipt.xml rename to receiptui/src/main/res/layout/receipt.xml diff --git a/receipt/src/main/res/values/colors.xml b/receiptui/src/main/res/values/colors.xml similarity index 100% rename from receipt/src/main/res/values/colors.xml rename to receiptui/src/main/res/values/colors.xml diff --git a/receipt/src/main/res/values/dimens.xml b/receiptui/src/main/res/values/dimens.xml similarity index 100% rename from receipt/src/main/res/values/dimens.xml rename to receiptui/src/main/res/values/dimens.xml diff --git a/receipt/src/main/res/values/strings.xml b/receiptui/src/main/res/values/strings.xml similarity index 100% rename from receipt/src/main/res/values/strings.xml rename to receiptui/src/main/res/values/strings.xml diff --git a/receipt/src/main/res/values/styles.xml b/receiptui/src/main/res/values/styles.xml similarity index 100% rename from receipt/src/main/res/values/styles.xml rename to receiptui/src/main/res/values/styles.xml diff --git a/receipt/src/main/res/xml/network_security_config.xml b/receiptui/src/main/res/xml/network_security_config.xml similarity index 100% rename from receipt/src/main/res/xml/network_security_config.xml rename to receiptui/src/main/res/xml/network_security_config.xml diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java b/receiptui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java similarity index 97% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java rename to receiptui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java index 0fd013e52..e7ac68fac 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java +++ b/receiptui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.rule; +package com.hyperwallet.android.ui.transfermethod.rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; @@ -35,7 +35,6 @@ public String getResourceContent(final String resourceName) { } private String getContent(final String resourceName) { - URL resource = classLoader.getResource(resourceName); InputStream inputStream = null; Writer writer = new StringWriter(); diff --git a/receipt/src/test/resources/authentication_token_response.json b/receiptui/src/test/resources/authentication_token_response.json similarity index 100% rename from receipt/src/test/resources/authentication_token_response.json rename to receiptui/src/test/resources/authentication_token_response.json diff --git a/receipt/src/test/resources/prepaid_card_receipt_credit_response.json b/receiptui/src/test/resources/prepaid_card_receipt_credit_response.json similarity index 100% rename from receipt/src/test/resources/prepaid_card_receipt_credit_response.json rename to receiptui/src/test/resources/prepaid_card_receipt_credit_response.json diff --git a/receipt/src/test/resources/prepaid_card_receipt_debit_response.json b/receiptui/src/test/resources/prepaid_card_receipt_debit_response.json similarity index 100% rename from receipt/src/test/resources/prepaid_card_receipt_debit_response.json rename to receiptui/src/test/resources/prepaid_card_receipt_debit_response.json diff --git a/receiptui/src/test/resources/prepaid_card_receipt_list_response.json b/receiptui/src/test/resources/prepaid_card_receipt_list_response.json new file mode 100644 index 000000000..e6539804c --- /dev/null +++ b/receiptui/src/test/resources/prepaid_card_receipt_list_response.json @@ -0,0 +1,103 @@ +{ + "data": [ + { + "journalId": "FISVL_5240220", + "type": "PREPAID_CARD_SALE", + "createdOn": "2019-06-06T22:48:41", + "entry": "DEBIT", + "destinationToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "10.00", + "fee": "3.00", + "currency": "USD", + "details": { + "cardNumber": "************0673", + "clientPaymentId": "AOxXefx9", + "payeeName": "A Person", + "website": "https://api.sandbox.hyperwallet.com", + "notes": "Sample prepaid card payment for the period of June 15th, 2019 to July 23, 2019", + "charityName": "Sample Charity", + "checkNumber": "Sample Check Number" + } + }, + { + "journalId": "FISVL_5240221", + "type": "DEPOSIT", + "createdOn": "2019-06-06T22:48:51", + "entry": "CREDIT", + "destinationToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "5.00", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240222", + "type": "ADJUSTMENT", + "createdOn": "2019-06-01T22:49:17", + "entry": "DEBIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "8.90", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240223", + "type": "ADJUSTMENT", + "createdOn": "2019-03-31T23:55:17", + "entry": "DEBIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "7.90", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240224", + "type": "ADJUSTMENT", + "createdOn": "2019-02-28T23:55:17", + "entry": "CREDIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "6.90", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240225", + "type": "ADJUSTMENT", + "createdOn": "2019-02-23T23:55:17", + "entry": "CREDIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "3.90", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + }, + { + "journalId": "FISA_5240226", + "type": "ADJUSTMENT", + "createdOn": "2019-02-21T23:55:17", + "entry": "CREDIT", + "sourceToken": "trm-2e02da75-a36c-4723-b613-0b64e6f582d9", + "amount": "9.92", + "currency": "USD", + "details": { + "cardNumber": "************0673" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://qamaster-hyperwallet.aws.paylution.net/rest/v3/users/usr-e17ae43b-284d-4198-9585-f417943c624f/prepaid-cards/trm-2e02da75-a36c-4723-b613-0b64e6f582d9/receipts" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/prepaid_card_receipt_unknown_type_response.json b/receiptui/src/test/resources/prepaid_card_receipt_unknown_type_response.json similarity index 100% rename from receipt/src/test/resources/prepaid_card_receipt_unknown_type_response.json rename to receiptui/src/test/resources/prepaid_card_receipt_unknown_type_response.json diff --git a/receipt/src/test/resources/receipt_credit_response.json b/receiptui/src/test/resources/receipt_credit_response.json similarity index 100% rename from receipt/src/test/resources/receipt_credit_response.json rename to receiptui/src/test/resources/receipt_credit_response.json diff --git a/receipt/src/test/resources/receipt_debit_response.json b/receiptui/src/test/resources/receipt_debit_response.json similarity index 100% rename from receipt/src/test/resources/receipt_debit_response.json rename to receiptui/src/test/resources/receipt_debit_response.json diff --git a/receiptui/src/test/resources/receipt_list_date_grouping_response.json b/receiptui/src/test/resources/receipt_list_date_grouping_response.json new file mode 100644 index 000000000..1b5b798bb --- /dev/null +++ b/receiptui/src/test/resources/receipt_list_date_grouping_response.json @@ -0,0 +1,90 @@ +{ + "count": 5, + "offset": 0, + "limit": 10, + "data": [ + { + "journalId": "51660665", + "type": "PAYMENT", + "createdOn": "2019-05-27T15:42:07", + "entry": "CREDIT", + "sourceToken": "act-b1f6dc28-e534-45f4-a661-3523f051f77a", + "destinationToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "amount": "5000.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "trans-0001", + "payeeName": "Kevin Puckett" + } + }, + { + "journalId": "51660666", + "type": "TRANSFER_TO_BANK_ACCOUNT", + "createdOn": "2019-05-27T15:57:49", + "entry": "DEBIT", + "sourceToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "destinationToken": "trm-0a2ac589-2cae-4ed3-9b0b-658246a34687", + "amount": "10.25", + "fee": "0.25", + "currency": "USD", + "details": { + "payeeName": "Kevin Puckett", + "bankAccountId": "patzachery.mcclary@example.com" + } + }, + { + "journalId": "51660667", + "type": "PAYMENT", + "createdOn": "2019-05-27T16:01:10", + "entry": "CREDIT", + "sourceToken": "act-b1f6dc28-e534-45f4-a661-3523f051f77a", + "destinationToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "amount": "11.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "trans-02", + "payeeName": "Kevin Puckett" + } + }, + { + "journalId": "51660675", + "type": "PAYMENT", + "createdOn": "2019-06-04T10:35:23", + "entry": "CREDIT", + "sourceToken": "act-b1f6dc28-e534-45f4-a661-3523f051f77a", + "destinationToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "amount": "13.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "CSietnRJQQ0bscYkOoPJxNiTDiVALhjQ", + "payeeName": "Kevin Puckett" + } + }, + { + "journalId": "51660676", + "type": "PAYMENT", + "createdOn": "2019-06-04T11:16:21", + "entry": "CREDIT", + "sourceToken": "act-b1f6dc28-e534-45f4-a661-3523f051f77a", + "destinationToken": "usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6", + "amount": "14.00", + "fee": "0.00", + "currency": "USD", + "details": { + "clientPaymentId": "wUOdfLlJONacbdHlAHOAXQT7uwX7LTPy", + "payeeName": "Kevin Puckett" + } + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-b4e8ec34-52d8-4a81-9566-bdde1bd745b6/receipts?offset=0&limit=10&createdAfter=2019-1-1" + } + ] +} \ No newline at end of file diff --git a/receipt/src/test/resources/receipt_list_paged_last_response.json b/receiptui/src/test/resources/receipt_list_paged_last_response.json similarity index 100% rename from receipt/src/test/resources/receipt_list_paged_last_response.json rename to receiptui/src/test/resources/receipt_list_paged_last_response.json diff --git a/receipt/src/test/resources/receipt_list_paged_response.json b/receiptui/src/test/resources/receipt_list_paged_response.json similarity index 100% rename from receipt/src/test/resources/receipt_list_paged_response.json rename to receiptui/src/test/resources/receipt_list_paged_response.json diff --git a/receipt/src/test/resources/receipt_list_paged_second_response.json b/receiptui/src/test/resources/receipt_list_paged_second_response.json similarity index 100% rename from receipt/src/test/resources/receipt_list_paged_second_response.json rename to receiptui/src/test/resources/receipt_list_paged_second_response.json diff --git a/receipt/src/test/resources/receipt_list_paged_third_response.json b/receiptui/src/test/resources/receipt_list_paged_third_response.json similarity index 100% rename from receipt/src/test/resources/receipt_list_paged_third_response.json rename to receiptui/src/test/resources/receipt_list_paged_third_response.json diff --git a/receipt/src/test/resources/receipt_list_response.json b/receiptui/src/test/resources/receipt_list_response.json similarity index 100% rename from receipt/src/test/resources/receipt_list_response.json rename to receiptui/src/test/resources/receipt_list_response.json diff --git a/receipt/src/test/resources/receipt_unknown_type_response.json b/receiptui/src/test/resources/receipt_unknown_type_response.json similarity index 100% rename from receipt/src/test/resources/receipt_unknown_type_response.json rename to receiptui/src/test/resources/receipt_unknown_type_response.json diff --git a/settings.gradle b/settings.gradle index 905f2e4e9..9058fac39 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':ui', ':common', ':receipt' +include ':transfermethodui', ':receiptui', ':commonui', ':receiptrepository', ':userrepository', ':transfermethodrepository', ':commonrepository' diff --git a/transfermethodrepository/.gitignore b/transfermethodrepository/.gitignore new file mode 100644 index 000000000..26b424a3f --- /dev/null +++ b/transfermethodrepository/.gitignore @@ -0,0 +1,3 @@ +/build + +*.exec diff --git a/transfermethodrepository/build.gradle b/transfermethodrepository/build.gradle new file mode 100644 index 000000000..5f8b12e95 --- /dev/null +++ b/transfermethodrepository/build.gradle @@ -0,0 +1,12 @@ +apply from: "$rootProject.projectDir/android-library.gradle" +description = 'Hyperwallet Transfer Method Repository SDK for Android to integrate with the Hyperwallet Platform' +project.ext { + mavenName = 'Hyperwallet Android Transfer Method Repository SDK' +} +apply from: "$rootProject.projectDir/publish.gradle" + +dependencies { + api project(':commonrepository') + testImplementation "org.robolectric:robolectric:$robolectricVersion" + testImplementation "com.squareup.okhttp3:mockwebserver:$mockWebServerVersion" +} \ No newline at end of file diff --git a/transfermethodrepository/config/jacoco-settings.gradle b/transfermethodrepository/config/jacoco-settings.gradle new file mode 100644 index 000000000..f1b0a7c45 --- /dev/null +++ b/transfermethodrepository/config/jacoco-settings.gradle @@ -0,0 +1,78 @@ +apply plugin: 'jacoco' + +final def jacocoVersion = "0.8.2" + +jacoco { + toolVersion = jacocoVersion +} + +android { + testOptions { + unitTests { + includeAndroidResources = true + returnDefaultValues = true + } + unitTests.all { + jacoco { + includeNoLocationClasses = true + } + } + } +} + +def fileFilter = ['**/BuildConfig.*'] + +def debugClassPaths = [ + '**/intermediates/javac/debug/*/classes/**' +] + +final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] + +task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { + + group = 'Reporting' + description = 'Generate Jacoco coverage reports.' + reports { + html { + enabled = true + destination file("$project.buildDir/reports/jacoco") + } + } + + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") +} + +task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { + + group = 'Verification' + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") + + violationRules { + setFailOnViolation(true) + + rule { + element = 'CLASS' + limit { + value = 'COVEREDRATIO' + counter = 'BRANCH' + minimum = 0.65 + } + } + } +} + diff --git a/transfermethodrepository/config/lint.xml b/transfermethodrepository/config/lint.xml new file mode 100644 index 000000000..9242eccb2 --- /dev/null +++ b/transfermethodrepository/config/lint.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/transfermethodrepository/proguard-rules.pro b/transfermethodrepository/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/transfermethodrepository/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/transfermethodrepository/src/main/AndroidManifest.xml b/transfermethodrepository/src/main/AndroidManifest.xml new file mode 100644 index 000000000..dfdab902d --- /dev/null +++ b/transfermethodrepository/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepository.java similarity index 97% rename from ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java rename to transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepository.java index 08c9694e3..31389ee50 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepository.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepository.java @@ -24,7 +24,7 @@ * USE OR OTHER DEALINGS * IN THE SOFTWARE. */ -package com.hyperwallet.android.ui.repository; +package com.hyperwallet.android.ui.transfermethod.repository; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImpl.java similarity index 96% rename from ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java rename to transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImpl.java index b8384793f..f9a382805 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImpl.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImpl.java @@ -24,7 +24,7 @@ * USE OR OTHER DEALINGS * IN THE SOFTWARE. */ -package com.hyperwallet.android.ui.repository; +package com.hyperwallet.android.ui.transfermethod.repository; import android.os.Handler; @@ -39,7 +39,7 @@ import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationKey; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationFieldQuery; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationKeysQuery; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; import java.util.HashMap; import java.util.Map; @@ -50,16 +50,12 @@ public class TransferMethodConfigurationRepositoryImpl implements TransferMethod private final Map mFieldMap; private HyperwalletTransferMethodConfigurationKey mTransferMethodConfigurationKey; - TransferMethodConfigurationRepositoryImpl() { + //todo use default modifier after RepositoryFactory is removed + public TransferMethodConfigurationRepositoryImpl() { mHandler = new Handler(); mFieldMap = new HashMap<>(); } - @VisibleForTesting - Hyperwallet getHyperwallet() { - return Hyperwallet.getDefault(); - } - @VisibleForTesting() protected TransferMethodConfigurationRepositoryImpl(@Nullable Handler handler, HyperwalletTransferMethodConfigurationKey transferMethodConfigurationKey, @@ -69,6 +65,11 @@ protected TransferMethodConfigurationRepositoryImpl(@Nullable Handler handler, mFieldMap = fieldMap; } + @VisibleForTesting + Hyperwallet getHyperwallet() { + return Hyperwallet.getDefault(); + } + @VisibleForTesting void getTransferMethodConfigurationKeyResult(final LoadKeysCallback loadKeysCallback) { HyperwalletTransferMethodConfigurationKeysQuery query = new HyperwalletTransferMethodConfigurationKeysQuery(); diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepository.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepository.java similarity index 98% rename from ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepository.java rename to transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepository.java index 37baebfc9..dce02d886 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepository.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepository.java @@ -14,7 +14,7 @@ * 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.repository; +package com.hyperwallet.android.ui.transfermethod.repository; import androidx.annotation.NonNull; 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 new file mode 100644 index 000000000..ed9360c6f --- /dev/null +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactory.java @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Hyperwallet Systems Inc. + * + * 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 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; + +public class TransferMethodRepositoryFactory { + private static TransferMethodRepositoryFactory sInstance; + private TransferMethodRepository mTransferMethodRepository; + private TransferMethodConfigurationRepository mTransferMethodConfigurationRepository; + + private TransferMethodRepositoryFactory() { + mTransferMethodRepository = new TransferMethodRepositoryImpl(); + mTransferMethodConfigurationRepository = new TransferMethodConfigurationRepositoryImpl(); + } + + public static synchronized TransferMethodRepositoryFactory getInstance() { + if (sInstance == null) { + sInstance = new TransferMethodRepositoryFactory(); + } + return sInstance; + } + + public static void clearInstance() { + sInstance = null; + } + + public TransferMethodRepository getTransferMethodRepository() { + return mTransferMethodRepository; + } + + public TransferMethodConfigurationRepository getTransferMethodConfigurationRepository() { + return mTransferMethodConfigurationRepository; + } +} diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImpl.java similarity index 99% rename from ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java rename to transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImpl.java index 17aab2028..69f450ec2 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImpl.java +++ b/transfermethodrepository/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImpl.java @@ -14,7 +14,7 @@ * 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.repository; +package com.hyperwallet.android.ui.transfermethod.repository; import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.ACTIVATED; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TOKEN; diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/FieldMapKeyTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/FieldMapKeyTest.java similarity index 94% rename from ui/src/test/java/com/hyperwallet/android/ui/repository/FieldMapKeyTest.java rename to transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/FieldMapKeyTest.java index 297575fa0..f0541bb9a 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/FieldMapKeyTest.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/FieldMapKeyTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.repository; +package com.hyperwallet.android.ui.transfermethod.repository; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImplTest.java similarity index 98% rename from ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java rename to transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImplTest.java index 7bcc36886..b71175ead 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodConfigurationRepositoryImplTest.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImplTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.repository; +package com.hyperwallet.android.ui.transfermethod.repository; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; @@ -32,7 +32,7 @@ import com.hyperwallet.android.model.graphql.keyed.HyperwalletTransferMethodConfigurationKeyResult; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationFieldQuery; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationKeysQuery; -import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.util.JsonUtils; import org.hamcrest.collection.IsEmptyCollection; diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/RepositoryFactoryTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactoryTest.java similarity index 65% rename from ui/src/test/java/com/hyperwallet/android/ui/repository/RepositoryFactoryTest.java rename to transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactoryTest.java index 050534fc8..7e89c5a03 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/RepositoryFactoryTest.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryFactoryTest.java @@ -1,43 +1,39 @@ -package com.hyperwallet.android.ui.repository; +package com.hyperwallet.android.ui.transfermethod.repository; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.notNullValue; import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -@RunWith(RobolectricTestRunner.class) -public class RepositoryFactoryTest { +public class TransferMethodRepositoryFactoryTest { @Test public void testGetInstance_verifyRepositoriesInitialized() { - RepositoryFactory repositoryFactory = RepositoryFactory.getInstance(); + TransferMethodRepositoryFactory repositoryFactory = TransferMethodRepositoryFactory.getInstance(); assertThat(repositoryFactory, is(notNullValue())); - assertThat(repositoryFactory.getTransferMethodConfigurationRepository(), is(notNullValue())); assertThat(repositoryFactory.getTransferMethodRepository(), is(notNullValue())); + assertThat(repositoryFactory.getTransferMethodConfigurationRepository(), is(notNullValue())); } @Test - public void testClearInstance_verifyRepositoriesCleared() { - RepositoryFactory repositoryFactory = RepositoryFactory.getInstance(); + public void testClearInstance_verifyRepositoryCleared() { + TransferMethodRepositoryFactory repositoryFactory = TransferMethodRepositoryFactory.getInstance(); + TransferMethodRepository transferMethodRepository = repositoryFactory.getTransferMethodRepository(); TransferMethodConfigurationRepository configurationRepository = repositoryFactory.getTransferMethodConfigurationRepository(); - TransferMethodRepository transferMethodRepository = repositoryFactory.getTransferMethodRepository(); - RepositoryFactory currentRepositoryFactory = RepositoryFactory.getInstance(); + TransferMethodRepositoryFactory currentRepositoryFactory = TransferMethodRepositoryFactory.getInstance(); assertThat(repositoryFactory, is(currentRepositoryFactory)); - assertThat(configurationRepository, is(currentRepositoryFactory.getTransferMethodConfigurationRepository())); assertThat(transferMethodRepository, is(currentRepositoryFactory.getTransferMethodRepository())); + assertThat(configurationRepository, is(currentRepositoryFactory.getTransferMethodConfigurationRepository())); - RepositoryFactory.clearInstance(); + TransferMethodRepositoryFactory.clearInstance(); - RepositoryFactory anotherRepositoryFactory = RepositoryFactory.getInstance(); + TransferMethodRepositoryFactory anotherRepositoryFactory = TransferMethodRepositoryFactory.getInstance(); assertThat(repositoryFactory, is(not(anotherRepositoryFactory))); + assertThat(transferMethodRepository, is(not(anotherRepositoryFactory.getTransferMethodRepository()))); assertThat(configurationRepository, is(not(anotherRepositoryFactory.getTransferMethodConfigurationRepository()))); - assertThat(transferMethodRepository, is(not(anotherRepositoryFactory.getTransferMethodRepository()))); } } \ No newline at end of file diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java similarity index 99% rename from ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java rename to transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java index 59c3d3ee9..0e7b396c0 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/TransferMethodRepositoryImplTest.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.repository; +package com.hyperwallet.android.ui.transfermethod.repository; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; diff --git a/ui/src/test/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java similarity index 97% rename from ui/src/test/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java rename to transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java index a983c9b7d..4db98b20a 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/rule/HyperwalletExternalResourceManager.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.rule; +package com.hyperwallet.android.ui.transfermethod.rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; diff --git a/ui/src/test/resources/error_tmc_keys_response.json b/transfermethodrepository/src/test/resources/error_tmc_keys_response.json similarity index 100% rename from ui/src/test/resources/error_tmc_keys_response.json rename to transfermethodrepository/src/test/resources/error_tmc_keys_response.json diff --git a/ui/src/test/resources/successful_tmc_fields_bank_account_response.json b/transfermethodrepository/src/test/resources/successful_tmc_fields_bank_account_response.json similarity index 100% rename from ui/src/test/resources/successful_tmc_fields_bank_account_response.json rename to transfermethodrepository/src/test/resources/successful_tmc_fields_bank_account_response.json diff --git a/ui/src/test/resources/successful_tmc_keys_response.json b/transfermethodrepository/src/test/resources/successful_tmc_keys_response.json similarity index 100% rename from ui/src/test/resources/successful_tmc_keys_response.json rename to transfermethodrepository/src/test/resources/successful_tmc_keys_response.json diff --git a/ui/.gitignore b/transfermethodui/.gitignore similarity index 100% rename from ui/.gitignore rename to transfermethodui/.gitignore diff --git a/transfermethodui/build.gradle b/transfermethodui/build.gradle new file mode 100644 index 000000000..fe72e3da1 --- /dev/null +++ b/transfermethodui/build.gradle @@ -0,0 +1,29 @@ +apply from: "$rootProject.projectDir/android-library.gradle" +description = 'Hyperwallet Transfer Method UI SDK for Android to integrate with the Hyperwallet Platform' +project.ext { + mavenName = 'Hyperwallet Android Transfer Method UI SDK' +} +apply from: "$rootProject.projectDir/publish.gradle" + +dependencies { + + implementation "androidx.appcompat:appcompat:$appcompatVersion" + implementation "androidx.constraintlayout:constraintlayout:$constraintlayoutVersion" + implementation "androidx.legacy:legacy-support-v4:$legacySupportV4Version" + implementation "androidx.recyclerview:recyclerview:$recycleViewVersion" + + implementation project(':commonui') + implementation project(":userrepository") + implementation project(":transfermethodrepository") + + + androidTestImplementation "androidx.test:rules:$testRulesVersion" + androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" + androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" + androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockServerVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanaryVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:$leakcanaryVersion" + + testImplementation "org.robolectric:robolectric:$robolectricVersion" + testImplementation "com.squareup.okhttp3:mockwebserver:$mockWebServerVersion" +} \ No newline at end of file diff --git a/ui/config/jacoco-settings.gradle b/transfermethodui/config/jacoco-settings.gradle similarity index 79% rename from ui/config/jacoco-settings.gradle rename to transfermethodui/config/jacoco-settings.gradle index 9cb13e331..725c470eb 100644 --- a/ui/config/jacoco-settings.gradle +++ b/transfermethodui/config/jacoco-settings.gradle @@ -21,13 +21,13 @@ android { } def fileFilter = ['**/BuildConfig.*', - '**/com/hyperwallet/android/ui/HyperwalletUi.*', - '**/com/hyperwallet/android/ui/**/*Activity*.*', - '**/com/hyperwallet/android/ui/**/*Fragment*.*', - '**/com/hyperwallet/android/ui/transfermethod/TransferMethodSelectionItem.*', - '**/com/hyperwallet/android/ui/transfermethod/TransferMethodUtils.*', - '**/com/hyperwallet/android/ui/view/HorizontalDividerItemDecorator.*', - '**/com/hyperwallet/android/ui/view/widget/*' + '**/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodUi.*', + '**/com/hyperwallet/android/ui/transfermethod/**/*Activity*.*', + '**/com/hyperwallet/android/ui/transfermethod/**/*Fragment*.*', + '**/com/hyperwallet/android/ui/transfermethod/view/TransferMethodSelectionItem.*', + '**/com/hyperwallet/android/ui/transfermethod/view/TransferMethodUtils.*', + '**/com/hyperwallet/android/ui/transfermethod/view/HorizontalDividerItemDecorator.*', + '**/com/hyperwallet/android/ui/transfermethod/view/widget/*' ] def debugClassPaths = [ '**/intermediates/javac/debug/*/classes/**' diff --git a/ui/config/lint.xml b/transfermethodui/config/lint.xml similarity index 100% rename from ui/config/lint.xml rename to transfermethodui/config/lint.xml diff --git a/transfermethodui/proguard-rules.pro b/transfermethodui/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/transfermethodui/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/ui/src/androidTest/AndroidManifest.xml b/transfermethodui/src/androidTest/AndroidManifest.xml similarity index 62% rename from ui/src/androidTest/AndroidManifest.xml rename to transfermethodui/src/androidTest/AndroidManifest.xml index 138dc247d..e1bac67e4 100644 --- a/ui/src/androidTest/AndroidManifest.xml +++ b/transfermethodui/src/androidTest/AndroidManifest.xml @@ -2,7 +2,7 @@ - + diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java similarity index 94% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java index 18989446a..243350ad1 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java @@ -22,7 +22,7 @@ import static java.net.HttpURLConnection.HTTP_OK; import static com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment.RESULT_ERROR; -import static com.hyperwallet.android.ui.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.nestedScrollTo; import android.app.Instrumentation; import android.content.Intent; @@ -36,12 +36,13 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; -import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity; import org.junit.After; import org.junit.Before; @@ -87,7 +88,7 @@ public void setup() { @After public void cleanup() { - RepositoryFactory.clearInstance(); + TransferMethodRepositoryFactory.clearInstance(); } @Before diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java similarity index 95% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java index 4ac416f78..414521218 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java @@ -24,11 +24,11 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount.Purpose.SAVINGS; -import static com.hyperwallet.android.ui.util.EspressoUtils.hasEmptyText; -import static com.hyperwallet.android.ui.util.EspressoUtils.hasErrorText; -import static com.hyperwallet.android.ui.util.EspressoUtils.hasNoErrorText; -import static com.hyperwallet.android.ui.util.EspressoUtils.nestedScrollTo; -import static com.hyperwallet.android.ui.util.EspressoUtils.withHint; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasEmptyText; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasNoErrorText; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withHint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -47,12 +47,13 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; -import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.ui.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.transfermethod.util.RecyclerViewCountAssertion; +import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity; import org.junit.After; import org.junit.Before; @@ -101,7 +102,7 @@ public void setup() { @After public void cleanup() { - RepositoryFactory.clearInstance(); + TransferMethodRepositoryFactory.clearInstance(); } @Before diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java similarity index 93% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java index 44ea7393f..508c397f8 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java @@ -22,10 +22,10 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.concurrent.TimeUnit.SECONDS; -import static com.hyperwallet.android.ui.util.EspressoUtils.hasEmptyText; -import static com.hyperwallet.android.ui.util.EspressoUtils.hasErrorText; -import static com.hyperwallet.android.ui.util.EspressoUtils.nestedScrollTo; -import static com.hyperwallet.android.ui.util.EspressoUtils.withHint; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasEmptyText; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withHint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -44,11 +44,12 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; -import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity; import org.junit.After; import org.junit.Before; @@ -105,7 +106,7 @@ public void setup() { @After public void cleanup() { - RepositoryFactory.clearInstance(); + TransferMethodRepositoryFactory.clearInstance(); } @Before diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/HyperwalletInstrumentedTestApplication.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/HyperwalletInstrumentedTestApplication.java similarity index 93% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/HyperwalletInstrumentedTestApplication.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/HyperwalletInstrumentedTestApplication.java index 1e77c01b7..5d3be31c5 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/HyperwalletInstrumentedTestApplication.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/HyperwalletInstrumentedTestApplication.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui; +package com.hyperwallet.android.ui.transfermethod; import android.app.Application; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java similarity index 97% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java index 01e3e1d29..d53840652 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java @@ -21,8 +21,8 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.DE_ACTIVATED; -import static com.hyperwallet.android.ui.util.EspressoUtils.atPosition; -import static com.hyperwallet.android.ui.util.EspressoUtils.withDrawable; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.atPosition; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withDrawable; import android.content.BroadcastReceiver; import android.content.Context; @@ -40,11 +40,12 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.model.HyperwalletStatusTransition; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.ui.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.transfermethod.util.RecyclerViewCountAssertion; +import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.transfermethod.view.ListTransferMethodActivity; import org.hamcrest.Matchers; import org.junit.After; @@ -77,7 +78,7 @@ public void setup() { @After public void cleanup() { - RepositoryFactory.clearInstance(); + TransferMethodRepositoryFactory.clearInstance(); } @Test diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java similarity index 91% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java index ebf34101b..f61bec357 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java @@ -24,10 +24,10 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.concurrent.TimeUnit.SECONDS; -import static com.hyperwallet.android.ui.util.EspressoUtils.hasEmptyText; -import static com.hyperwallet.android.ui.util.EspressoUtils.hasErrorText; -import static com.hyperwallet.android.ui.util.EspressoUtils.nestedScrollTo; -import static com.hyperwallet.android.ui.util.EspressoUtils.withHint; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasEmptyText; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withHint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -46,11 +46,12 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; -import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity; import org.junit.After; import org.junit.Before; @@ -95,7 +96,7 @@ public void setup() { @After public void cleanup() { - RepositoryFactory.clearInstance(); + TransferMethodRepositoryFactory.clearInstance(); } @Before diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java similarity index 94% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java index 5c3ace145..68acebad9 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java @@ -25,12 +25,12 @@ import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; import static com.hyperwallet.android.model.user.HyperwalletUser.ProfileTypes.BUSINESS; import static com.hyperwallet.android.model.user.HyperwalletUser.ProfileTypes.INDIVIDUAL; -import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_COUNTRY; -import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY; -import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE; -import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_TYPE; -import static com.hyperwallet.android.ui.util.EspressoUtils.atPosition; -import static com.hyperwallet.android.ui.util.EspressoUtils.withDrawable; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.atPosition; +import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withDrawable; +import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_COUNTRY; +import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY; +import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE; +import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_TYPE; import android.widget.TextView; @@ -43,12 +43,14 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.common.util.EspressoIdlingResource; -import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.ui.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.transfermethod.util.RecyclerViewCountAssertion; +import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; +import com.hyperwallet.android.ui.transfermethod.view.SelectTransferMethodActivity; +import com.hyperwallet.android.ui.user.repository.UserRepositoryFactory; import org.junit.After; import org.junit.Before; @@ -81,7 +83,8 @@ public void setup() { @After public void cleanup() { - RepositoryFactory.clearInstance(); + TransferMethodRepositoryFactory.clearInstance(); + UserRepositoryFactory.clearInstance(); } @Before diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java new file mode 100644 index 000000000..68e288a5b --- /dev/null +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java @@ -0,0 +1,73 @@ +package com.hyperwallet.android.ui.transfermethod.rule; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class HyperwalletExternalResourceManager extends TestWatcher { + + private static final String EMPTY = ""; + private ClassLoader classLoader; + private Logger logger; + + @Override + protected void starting(Description description) { + super.starting(description); + classLoader = description.getTestClass().getClassLoader(); + logger = Logger.getLogger(description.getTestClass().getName()); + } + + public String getResourceContent(final String resourceName) { + if (resourceName == null) { + throw new IllegalArgumentException("Parameter resourceName cannot be null"); + } + + return getContent(resourceName); + } + + private String getContent(final String resourceName) { + + URL resource = classLoader.getResource(resourceName); + InputStream inputStream = null; + Writer writer = new StringWriter(); + String resourceContent = EMPTY; + if (resource != null) { + try { + inputStream = resource.openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + String line = reader.readLine(); + while (line != null) { + writer.write(line); + line = reader.readLine(); + } + resourceContent = writer.toString(); + + } catch (Exception e) { + logger.log(Level.WARNING, "There was an error loading an external resource", e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "There was an error closing input stream", e); + } + try { + writer.close(); + } catch (IOException e) { + logger.log(Level.SEVERE, "There was an error closing writer", e); + } + } + } + return resourceContent; + } +} diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletMockWebServer.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletMockWebServer.java similarity index 98% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletMockWebServer.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletMockWebServer.java index fd37ac735..21cd2ae99 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/rule/HyperwalletMockWebServer.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletMockWebServer.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.rule; +package com.hyperwallet.android.ui.transfermethod.rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/util/EspressoUtils.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/EspressoUtils.java similarity index 99% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/util/EspressoUtils.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/EspressoUtils.java index 72891a832..fbd325c31 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/util/EspressoUtils.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/EspressoUtils.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.util; +package com.hyperwallet.android.ui.transfermethod.util; import android.graphics.Bitmap; import android.graphics.Canvas; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/util/NestedScrollToAction.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/NestedScrollToAction.java similarity index 95% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/util/NestedScrollToAction.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/NestedScrollToAction.java index 54f08aed7..63a6803f7 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/util/NestedScrollToAction.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/NestedScrollToAction.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.util; +package com.hyperwallet.android.ui.transfermethod.util; import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/util/RecyclerViewCountAssertion.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/RecyclerViewCountAssertion.java similarity index 93% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/util/RecyclerViewCountAssertion.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/RecyclerViewCountAssertion.java index e3c7945fd..1c9ec2479 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/util/RecyclerViewCountAssertion.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/RecyclerViewCountAssertion.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.util; +package com.hyperwallet.android.ui.transfermethod.util; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/ui/src/androidTest/java/com/hyperwallet/android/ui/util/TestAuthenticationProvider.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/TestAuthenticationProvider.java similarity index 96% rename from ui/src/androidTest/java/com/hyperwallet/android/ui/util/TestAuthenticationProvider.java rename to transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/TestAuthenticationProvider.java index 1f8350f8f..739423e40 100644 --- a/ui/src/androidTest/java/com/hyperwallet/android/ui/util/TestAuthenticationProvider.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/TestAuthenticationProvider.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.util; +package com.hyperwallet.android.ui.transfermethod.util; import com.hyperwallet.android.HyperwalletAuthenticationTokenListener; import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; diff --git a/ui/src/main/AndroidManifest.xml b/transfermethodui/src/main/AndroidManifest.xml similarity index 91% rename from ui/src/main/AndroidManifest.xml rename to transfermethodui/src/main/AndroidManifest.xml index 6888120a5..b7c92a689 100644 --- a/ui/src/main/AndroidManifest.xml +++ b/transfermethodui/src/main/AndroidManifest.xml @@ -7,13 +7,13 @@ diff --git a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletLocalBroadcast.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodLocalBroadcast.java similarity index 86% rename from ui/src/main/java/com/hyperwallet/android/ui/HyperwalletLocalBroadcast.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodLocalBroadcast.java index 7eed4cec5..e10b351ef 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletLocalBroadcast.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodLocalBroadcast.java @@ -14,10 +14,10 @@ * 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; +package com.hyperwallet.android.ui.transfermethod; -import static com.hyperwallet.android.ui.HyperwalletLocalBroadcast.HyperwalletLocalBroadcastAction.ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED; -import static com.hyperwallet.android.ui.HyperwalletLocalBroadcast.HyperwalletLocalBroadcastAction.ACTION_HYPERWALLET_TRANSFER_METHOD_DEACTIVATED; +import static com.hyperwallet.android.ui.transfermethod.HyperwalletTransferMethodLocalBroadcast.HyperwalletLocalBroadcastAction.ACTION_HYPERWALLET_TRANSFER_METHOD_ADDED; +import static com.hyperwallet.android.ui.transfermethod.HyperwalletTransferMethodLocalBroadcast.HyperwalletLocalBroadcastAction.ACTION_HYPERWALLET_TRANSFER_METHOD_DEACTIVATED; import android.content.Intent; import android.os.Parcelable; @@ -31,7 +31,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -public class HyperwalletLocalBroadcast { +public class HyperwalletTransferMethodLocalBroadcast { private static final String HYPERWALLET_LOCAL_BROADCAST_PAYLOAD_KEY = "hyperwallet-local-broadcast-payload"; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodUi.java similarity index 63% rename from ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodUi.java index 21e5ac913..6f3519205 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/HyperwalletUi.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodUi.java @@ -1,4 +1,3 @@ - /* * Copyright 2018 Hyperwallet * @@ -16,14 +15,12 @@ * 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; -package com.hyperwallet.android.ui; - -import static com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity.EXTRA_PREPAID_CARD_TOKEN; -import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_COUNTRY; -import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY; -import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE; -import static com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_TYPE; +import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_COUNTRY; +import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY; +import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE; +import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_TYPE; import android.content.Context; import android.content.Intent; @@ -32,32 +29,30 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; -import com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity; -import com.hyperwallet.android.ui.receipt.view.ListUserReceiptActivity; -import com.hyperwallet.android.ui.transfermethod.AddTransferMethodActivity; -import com.hyperwallet.android.ui.transfermethod.ListTransferMethodActivity; -import com.hyperwallet.android.ui.transfermethod.SelectTransferMethodActivity; +import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity; +import com.hyperwallet.android.ui.transfermethod.view.ListTransferMethodActivity; +import com.hyperwallet.android.ui.transfermethod.view.SelectTransferMethodActivity; /** * Class responsible for initializing the Hyperwallet UI SDK. It contains methods to interact with the activities and * fragments used to interact with the Hyperwallet platform */ -public final class HyperwalletUi { +public final class HyperwalletTransferMethodUi { - private static HyperwalletUi sInstance; + private static HyperwalletTransferMethodUi sInstance; - private HyperwalletUi() { + private HyperwalletTransferMethodUi() { } /** * @param authenticationTokenProvider An implementation of the {@link HyperwalletAuthenticationTokenProvider} - * @return Returns a newly created HyperwalletUi that can be used to get Intents to launch different + * @return Returns a newly created HyperwalletTransferMethodUi that can be used to get Intents to launch different * activities. */ - public static synchronized HyperwalletUi getInstance( + public static synchronized HyperwalletTransferMethodUi getInstance( @NonNull final HyperwalletAuthenticationTokenProvider authenticationTokenProvider) { if (sInstance == null) { - sInstance = new HyperwalletUi(); + sInstance = new HyperwalletTransferMethodUi(); Hyperwallet.getInstance(authenticationTokenProvider); } return sInstance; @@ -81,30 +76,16 @@ public Intent getIntentSelectTransferMethodActivity(@NonNull final Context conte return new Intent(context, SelectTransferMethodActivity.class); } - /** - * @param context A Context of the application consuming this Intent. - * @return an Intent with the data necessary to launch the {@link ListUserReceiptActivity} - */ - public Intent getIntentListUserReceiptActivity(@NonNull final Context context) { - return new Intent(context, ListUserReceiptActivity.class); - } - - /** - * @param context A Context of the application consuming this Intent. - * @return an Intent with the data necessary to launch the {@link ListPrepaidCardReceiptActivity} - */ - public Intent getIntentListPrepaidCardReceiptActivity(@NonNull final Context context, @NonNull final String token) { - Intent intent = new Intent(context, ListPrepaidCardReceiptActivity.class); - intent.putExtra(EXTRA_PREPAID_CARD_TOKEN, token); - return intent; - } - /** * @param context A Context of the application consuming this Intent. * @param country The transfer method country code. ISO 3166-1 alpha-2 format. * @param currency The transfer method currency code. ISO 4217 format. * @param transferMethodType The type of transfer method. For a complete list of transfer methods, see {@link - * com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes} + * + * + * + * + * com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes} * @param profileType The type of the account holder profile. For a complete list of options, see * {@link com.hyperwallet.android.model.user.HyperwalletUser.ProfileTypes} * @return an Intent with the data necessary to launch the {@link AddTransferMethodActivity} diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodActivity.java similarity index 97% rename from ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodActivity.java index 9c1fa1d77..e3ba27b72 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodActivity.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodActivity.java @@ -14,7 +14,7 @@ * 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; +package com.hyperwallet.android.ui.transfermethod.view; import android.os.Bundle; import android.view.View; @@ -32,8 +32,6 @@ import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; -import com.hyperwallet.android.ui.view.WidgetDateDialogFragment; -import com.hyperwallet.android.ui.view.WidgetSelectionDialogFragment; import java.util.List; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodContract.java similarity index 98% rename from ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodContract.java index 959e0a03e..1b7a43fcf 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodContract.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodContract.java @@ -14,7 +14,7 @@ * 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; +package com.hyperwallet.android.ui.transfermethod.view; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodFragment.java similarity index 96% rename from ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodFragment.java index 447624e31..6a9367128 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodFragment.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodFragment.java @@ -14,7 +14,7 @@ * 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; +package com.hyperwallet.android.ui.transfermethod.view; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.PROFILE_TYPE; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY; @@ -55,18 +55,16 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletBankCard; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.model.transfermethod.PayPalAccount; -import com.hyperwallet.android.ui.HyperwalletLocalBroadcast; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.repository.RepositoryFactory; -import com.hyperwallet.android.ui.view.WidgetDateDialogFragment; -import com.hyperwallet.android.ui.view.WidgetSelectionDialogFragment; -import com.hyperwallet.android.ui.view.widget.AbstractWidget; -import com.hyperwallet.android.ui.view.widget.DateChangedListener; -import com.hyperwallet.android.ui.view.widget.DateUtils; -import com.hyperwallet.android.ui.view.widget.DateWidget; -import com.hyperwallet.android.ui.view.widget.WidgetEventListener; -import com.hyperwallet.android.ui.view.widget.WidgetFactory; -import com.hyperwallet.android.ui.view.widget.WidgetInputState; +import com.hyperwallet.android.ui.transfermethod.HyperwalletTransferMethodLocalBroadcast; +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.DateUtils; +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; @@ -84,7 +82,7 @@ public class AddTransferMethodFragment extends Fragment implements WidgetEventLi private static final String ARGUMENT_TRANSFER_METHOD = "ARGUMENT_TRANSFER_METHOD"; private static final String ARGUMENT_WIDGET_STATE_MAP = "ARGUMENT_WIDGET_STATE_MAP"; private static final boolean FORCE_UPDATE = false; - + private final DateUtils mDateUtils = new DateUtils(); private String mCountry; private View mCreateButtonProgressBar; private Button mCreateTransferMethodButton; @@ -100,7 +98,6 @@ public class AddTransferMethodFragment extends Fragment implements WidgetEventLi private HyperwalletTransferMethod mTransferMethod; private String mTransferMethodProfileType; private HashMap mWidgetInputStateHashMap; - private final DateUtils mDateUtils = new DateUtils(); /** * Please do not use this to have instance of AddTransferMethodFragment this is reserved for android framework @@ -202,7 +199,7 @@ public void onClick(View v) { public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - RepositoryFactory factory = RepositoryFactory.getInstance(); + TransferMethodRepositoryFactory factory = TransferMethodRepositoryFactory.getInstance(); mPresenter = new AddTransferMethodPresenter(this, factory.getTransferMethodConfigurationRepository(), factory.getTransferMethodRepository()); @@ -296,7 +293,8 @@ public void saveTextChanged(@NonNull final String fieldName, @NonNull final Stri @Override public void notifyTransferMethodAdded(@NonNull final HyperwalletTransferMethod transferMethod) { - Intent intent = HyperwalletLocalBroadcast.createBroadcastIntentTransferMethodAdded(transferMethod); + Intent intent = HyperwalletTransferMethodLocalBroadcast.createBroadcastIntentTransferMethodAdded( + transferMethod); LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); getActivity().setResult(Activity.RESULT_OK); getActivity().finish(); @@ -484,14 +482,6 @@ public void openWidgetSelectionFragmentDialog(@NonNull final TreeMap errors); - } - - interface OnAddTransferMethodNetworkErrorCallback { - void showErrorsAddTransferMethod(@NonNull final List errors); - } - private void triggerSubmit() { if (performValidation(true)) { switch (mTransferMethodType) { @@ -623,4 +613,12 @@ void onDateSelected(@NonNull final String selectedValue, @NonNull final String f } } } + + interface OnLoadTransferMethodConfigurationFieldsNetworkErrorCallback { + void showErrorsLoadTransferMethodConfigurationFields(@NonNull final List errors); + } + + interface OnAddTransferMethodNetworkErrorCallback { + void showErrorsAddTransferMethod(@NonNull final List errors); + } } diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodPresenter.java similarity index 95% rename from ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodPresenter.java index d0fd40750..2355d4448 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenter.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodPresenter.java @@ -14,15 +14,15 @@ * 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; +package com.hyperwallet.android.ui.transfermethod.view; import androidx.annotation.NonNull; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.graphql.HyperwalletTransferMethodConfigurationField; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; -import com.hyperwallet.android.ui.repository.TransferMethodConfigurationRepository; -import com.hyperwallet.android.ui.repository.TransferMethodRepository; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodConfigurationRepository; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepository; public class AddTransferMethodPresenter implements AddTransferMethodContract.Presenter { diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/CountrySelectionDialogFragment.java similarity index 99% rename from ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/CountrySelectionDialogFragment.java index 66980f24b..d7cc52d15 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/CountrySelectionDialogFragment.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/CountrySelectionDialogFragment.java @@ -14,7 +14,7 @@ * 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.view; +package com.hyperwallet.android.ui.transfermethod.view; import android.app.Activity; import android.app.SearchManager; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/CurrencySelectionDialogFragment.java similarity index 99% rename from ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/CurrencySelectionDialogFragment.java index e9ee2bde1..5a0757605 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/view/CurrencySelectionDialogFragment.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/CurrencySelectionDialogFragment.java @@ -14,7 +14,7 @@ * 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.view; +package com.hyperwallet.android.ui.transfermethod.view; import android.app.Activity; import android.app.SearchManager; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/FeeFormatter.java similarity index 98% rename from ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/FeeFormatter.java index e073e0a1b..a5eba963f 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/FeeFormatter.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/FeeFormatter.java @@ -16,7 +16,7 @@ * IN THE SOFTWARE. */ -package com.hyperwallet.android.ui.transfermethod; +package com.hyperwallet.android.ui.transfermethod.view; import android.content.Context; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodActivity.java similarity index 98% rename from ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodActivity.java index 6aef7e314..4e4cdac20 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodActivity.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodActivity.java @@ -14,9 +14,9 @@ * 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; +package com.hyperwallet.android.ui.transfermethod.view; -import static com.hyperwallet.android.ui.transfermethod.ListTransferMethodFragment.ARGUMENT_IS_TRANSFER_METHODS_RELOAD_NEEDED; +import static com.hyperwallet.android.ui.transfermethod.view.ListTransferMethodFragment.ARGUMENT_IS_TRANSFER_METHODS_RELOAD_NEEDED; import android.content.Intent; import android.os.Bundle; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodContract.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodContract.java similarity index 97% rename from ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodContract.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodContract.java index 0b2e0e5ad..7727cd404 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodContract.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodContract.java @@ -14,7 +14,7 @@ * 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; +package com.hyperwallet.android.ui.transfermethod.view; import androidx.annotation.NonNull; diff --git a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodFragment.java similarity index 95% rename from ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java rename to transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodFragment.java index e38385540..77236a1a3 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodFragment.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodFragment.java @@ -14,13 +14,13 @@ * 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; +package com.hyperwallet.android.ui.transfermethod.view; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TYPE; -import static com.hyperwallet.android.ui.transfermethod.TransferMethodUtils.getStringFontIcon; -import static com.hyperwallet.android.ui.transfermethod.TransferMethodUtils.getStringResourceByName; -import static com.hyperwallet.android.ui.transfermethod.TransferMethodUtils.getTransferMethodDetail; +import static com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils.getStringFontIcon; +import static com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils.getStringResourceByName; +import static com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils.getTransferMethodDetail; import android.content.Context; import android.content.Intent; @@ -46,11 +46,11 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletStatusTransition; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; -import com.hyperwallet.android.ui.HyperwalletLocalBroadcast; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.common.view.HorizontalDividerItemDecorator; import com.hyperwallet.android.ui.common.view.OneClickListener; -import com.hyperwallet.android.ui.repository.RepositoryFactory; +import com.hyperwallet.android.ui.transfermethod.HyperwalletTransferMethodLocalBroadcast; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; import java.util.ArrayList; import java.util.List; @@ -179,7 +179,7 @@ public void onOneClick(View v) { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - RepositoryFactory factory = RepositoryFactory.getInstance(); + TransferMethodRepositoryFactory factory = TransferMethodRepositoryFactory.getInstance(); mPresenter = new ListTransferMethodPresenter(factory.getTransferMethodRepository(), this); } @@ -224,7 +224,7 @@ public void displayTransferMethods(@Nullable final List + tools:context="com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity"> diff --git a/ui/src/main/res/layout/activity_list_transfer_method.xml b/transfermethodui/src/main/res/layout/activity_list_transfer_method.xml similarity index 94% rename from ui/src/main/res/layout/activity_list_transfer_method.xml rename to transfermethodui/src/main/res/layout/activity_list_transfer_method.xml index 28ed9e27a..a065a9e0e 100644 --- a/ui/src/main/res/layout/activity_list_transfer_method.xml +++ b/transfermethodui/src/main/res/layout/activity_list_transfer_method.xml @@ -5,7 +5,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="com.hyperwallet.android.ui.transfermethod.ListTransferMethodActivity"> + tools:context="com.hyperwallet.android.ui.transfermethod.view.ListTransferMethodActivity"> \ No newline at end of file diff --git a/ui/src/main/res/layout/dialog_fragment_country_selection.xml b/transfermethodui/src/main/res/layout/dialog_fragment_country_selection.xml similarity index 100% rename from ui/src/main/res/layout/dialog_fragment_country_selection.xml rename to transfermethodui/src/main/res/layout/dialog_fragment_country_selection.xml diff --git a/ui/src/main/res/layout/dialog_fragment_currency_selection.xml b/transfermethodui/src/main/res/layout/dialog_fragment_currency_selection.xml similarity index 100% rename from ui/src/main/res/layout/dialog_fragment_currency_selection.xml rename to transfermethodui/src/main/res/layout/dialog_fragment_currency_selection.xml diff --git a/ui/src/main/res/layout/dialog_fragment_widget_selection.xml b/transfermethodui/src/main/res/layout/dialog_fragment_widget_selection.xml similarity index 100% rename from ui/src/main/res/layout/dialog_fragment_widget_selection.xml rename to transfermethodui/src/main/res/layout/dialog_fragment_widget_selection.xml diff --git a/ui/src/main/res/layout/fragment_add_transfer_method.xml b/transfermethodui/src/main/res/layout/fragment_add_transfer_method.xml similarity index 99% rename from ui/src/main/res/layout/fragment_add_transfer_method.xml rename to transfermethodui/src/main/res/layout/fragment_add_transfer_method.xml index 861e1bdcd..a4e56297a 100644 --- a/ui/src/main/res/layout/fragment_add_transfer_method.xml +++ b/transfermethodui/src/main/res/layout/fragment_add_transfer_method.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context="com.hyperwallet.android.ui.transfermethod.AddTransferMethodFragment"> + tools:context="com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodFragment"> + tools:context="com.hyperwallet.android.ui.transfermethod.view.ListTransferMethodFragment"> + tools:context="com.hyperwallet.android.ui.transfermethod.view.SelectTransferMethodFragment"> + + + + + \ No newline at end of file diff --git a/userrepository/proguard-rules.pro b/userrepository/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/userrepository/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/userrepository/src/main/AndroidManifest.xml b/userrepository/src/main/AndroidManifest.xml new file mode 100644 index 000000000..3ad5d3779 --- /dev/null +++ b/userrepository/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepository.java b/userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepository.java similarity index 97% rename from ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepository.java rename to userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepository.java index 777b7583a..cfbfaafa3 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepository.java +++ b/userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepository.java @@ -15,8 +15,7 @@ * 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.repository; +package com.hyperwallet.android.ui.user.repository; import androidx.annotation.NonNull; @@ -54,4 +53,4 @@ interface LoadUserCallback { void onError(@NonNull final HyperwalletErrors errors); } -} +} \ No newline at end of file diff --git a/userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepositoryFactory.java b/userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepositoryFactory.java new file mode 100644 index 000000000..2a117e981 --- /dev/null +++ b/userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepositoryFactory.java @@ -0,0 +1,25 @@ +package com.hyperwallet.android.ui.user.repository; + +public class UserRepositoryFactory { + private static UserRepositoryFactory sInstance; + private UserRepository mUserRepository; + + private UserRepositoryFactory() { + mUserRepository = new UserRepositoryImpl(); + } + + public static synchronized UserRepositoryFactory getInstance() { + if (sInstance == null) { + sInstance = new UserRepositoryFactory(); + } + return sInstance; + } + + public static void clearInstance() { + sInstance = null; + } + + public UserRepository getUserRepository() { + return mUserRepository; + } +} diff --git a/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepositoryImpl.java b/userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepositoryImpl.java similarity index 98% rename from ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepositoryImpl.java rename to userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepositoryImpl.java index 524849db2..af6d47b82 100644 --- a/ui/src/main/java/com/hyperwallet/android/ui/repository/UserRepositoryImpl.java +++ b/userrepository/src/main/java/com/hyperwallet/android/ui/user/repository/UserRepositoryImpl.java @@ -16,7 +16,7 @@ * THE SOFTWARE. */ -package com.hyperwallet.android.ui.repository; +package com.hyperwallet.android.ui.user.repository; import android.os.Handler; diff --git a/userrepository/src/test/java/com/hyperwallet/android/ui/user/repository/UserRepositoryFactoryTest.java b/userrepository/src/test/java/com/hyperwallet/android/ui/user/repository/UserRepositoryFactoryTest.java new file mode 100644 index 000000000..a320a6e1a --- /dev/null +++ b/userrepository/src/test/java/com/hyperwallet/android/ui/user/repository/UserRepositoryFactoryTest.java @@ -0,0 +1,34 @@ +package com.hyperwallet.android.ui.user.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; + +import org.junit.Test; + +public class UserRepositoryFactoryTest { + + @Test + public void testGetInstance_verifyRepositoriesInitialized() { + UserRepositoryFactory userRepositoryFactory = UserRepositoryFactory.getInstance(); + assertThat(userRepositoryFactory, is(notNullValue())); + assertThat(userRepositoryFactory.getUserRepository(), is(notNullValue())); + } + + @Test + public void testClearInstance_verifyRepositoriesCleared() { + UserRepositoryFactory userRepositoryFactory = UserRepositoryFactory.getInstance(); + + UserRepository userConfigurationRepository = userRepositoryFactory.getUserRepository(); + + UserRepositoryFactory currentRepositoryFactory = UserRepositoryFactory.getInstance(); + assertThat(userRepositoryFactory, is(currentRepositoryFactory)); + + UserRepositoryFactory.clearInstance(); + + UserRepositoryFactory anotherRepositoryFactory = UserRepositoryFactory.getInstance(); + assertThat(userRepositoryFactory, is(not(anotherRepositoryFactory))); + assertThat(userConfigurationRepository, is(not(anotherRepositoryFactory.getUserRepository()))); + } +} diff --git a/ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java b/userrepository/src/test/java/com/hyperwallet/android/ui/user/repository/UserRepositoryImplTest.java similarity index 97% rename from ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java rename to userrepository/src/test/java/com/hyperwallet/android/ui/user/repository/UserRepositoryImplTest.java index d35c7fa3a..c693c773d 100644 --- a/ui/src/test/java/com/hyperwallet/android/ui/repository/UserRepositoryImplTest.java +++ b/userrepository/src/test/java/com/hyperwallet/android/ui/user/repository/UserRepositoryImplTest.java @@ -1,9 +1,8 @@ -package com.hyperwallet.android.ui.repository; +package com.hyperwallet.android.ui.user.repository; +import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.nullValue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -22,6 +21,7 @@ import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.user.HyperwalletUser; +import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -135,7 +135,7 @@ public Object answer(InvocationOnMock invocation) { verify(mMockCallback, never()).onError(any(HyperwalletErrors.class)); HyperwalletUser user = mUserCaptor.getValue(); - assertThat(user, is(nullValue())); + assertThat(user, is(Matchers.nullValue())); } From aa085bc3c0a64c5568cecaedaf27b7245847e47c Mon Sep 17 00:00:00 2001 From: Flavio Mattos Date: Mon, 22 Jul 2019 14:32:19 -0700 Subject: [PATCH 028/177] preparing release beta03 --- CHANGELOG.md | 11 ++++++++--- README.md | 17 ++++++++++------- build.gradle | 2 +- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c167f1c0b..53c3b8ea4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,17 @@ Changelog ========= -1.0.0-beta01 +[1.0.0-beta01](https://github.com/hyperwallet/hyperwallet-android-ui-sdk/releases/tag/1.0.0-beta01) ------------------- - Initial release * UI components to create Bank Account and Bank Card for United States (USD) * UI components to list and deactivate accounts -1.0.0-beta02 +[1.0.0-beta02](https://github.com/hyperwallet/hyperwallet-android-ui-sdk/releases/tag/1.0.0-beta02) ------------------- -* Added PayPal as a Transfer method \ No newline at end of file +* Added PayPal as a Transfer method + +[1.0.0-beta03](https://github.com/hyperwallet/hyperwallet-android-ui-sdk/releases/tag/1.0.0-beta03) +------------------- +* Added support to list Users and Prepaid Card receipts +* Split project into multiple deliverable artifacts \ No newline at end of file diff --git a/README.md b/README.md index 96ba8f126..3d39ea1fc 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,11 @@ Note that this SDK is geared towards those who need both backend data and UI fea ## Installation -To install Hyperwallet UI SDK, you just need to add the dependency into your build.gradle file in Android Studio (or Gradle). For example: +To install Hyperwallet UI SDK, you just need to add the dependencies into your build.gradle file in Android Studio (or Gradle). For example: ```bash -api 'com.hyperwallet.android.ui:ui-sdk:1.0.0-beta02' +api 'com.hyperwallet.android.ui:transfermethodui:1.0.0-beta03' +api 'com.hyperwallet.android.ui:receiptui:1.0.0-beta03' ``` ## Initialization @@ -25,10 +26,12 @@ After you're done installing the SDK, you need to initialize an instance in orde ```java // initialize UI SDK -Hyperwallet.getInstance(hyperwalletAuthenticationTokenProvider) +HyperwalletReceiptUi.getInstance(hyperwalletAuthenticationTokenProvider); +HyperwalletTransferMethodUi.getInstance(hyperwalletAuthenticationTokenProvider); // use UI SDK functions -Hyperwallet.getDefault().getIntentListTransferMethodActivity(MainActivity.this); +mHyperwalletTransferMethodUi.getIntentListTransferMethodActivity(MainActivity.this); +mHyperwalletReceiptUi.getIntentListUserReceiptActivity(MainActivity.this); ``` ## Authentication @@ -88,7 +91,7 @@ The functions in UI SDK are available to use once the authentication is done. ``` @Override public void onClick(View view) { - Intent it = Hyperwallet.getDefault().getIntentListTransferMethodActivity(MainActivity.this); + Intent it = mHyperwalletTransferMethodUi.getIntentListTransferMethodActivity(MainActivity.this); startActivity(it); } ``` @@ -98,7 +101,7 @@ public void onClick(View view) { ``` @Override public void onClick(View view) { - Intent it = Hyperwallet.getDefault().getIntentSelectTransferMethodActivity(MainActivity.this); + Intent it = mHyperwalletTransferMethodUi.getIntentSelectTransferMethodActivity(MainActivity.this); startActivity(it); } ``` @@ -107,7 +110,7 @@ public void onClick(View view) { ``` @Override public void onClick(View view) { - Intent it = mHyperwalletUi.getIntentAddTransferMethodActivity(MainActivity.this, + Intent it = mHyperwalletTransferMethodUi.getIntentAddTransferMethodActivity(MainActivity.this, "US", "USD", "BANK_ACCOUNT"); diff --git a/build.gradle b/build.gradle index cf6d27824..bc5d01c1d 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ allprojects { } - project.version = "1.0.0-beta03-SNAPSHOT" + project.version = "1.0.0-beta03" } From 9b94a9a9588b6c70733da4d52b1f478e46b42f21 Mon Sep 17 00:00:00 2001 From: Flavio Mattos Date: Mon, 22 Jul 2019 15:36:14 -0700 Subject: [PATCH 029/177] fix errors after merge --- .../repository/UserRepositoryImplTest.java | 197 ------------------ .../repository/UserRepository.java | 57 ----- .../repository/UserRepositoryImpl.java | 71 ------- .../resources/user_business_response.json | 2 +- 4 files changed, 1 insertion(+), 326 deletions(-) delete mode 100644 transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepositoryImplTest.java delete mode 100644 transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepository.java delete mode 100644 transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepositoryImpl.java diff --git a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepositoryImplTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepositoryImplTest.java deleted file mode 100644 index 0f54ad10f..000000000 --- a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepositoryImplTest.java +++ /dev/null @@ -1,197 +0,0 @@ -package com.hyperwallet.android.ui.repository; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.nullValue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import static com.hyperwallet.android.model.HyperwalletUser.ProfileTypes.INDIVIDUAL; -import static com.hyperwallet.android.model.HyperwalletUser.UserStatuses.PRE_ACTIVATED; -import static com.hyperwallet.android.model.HyperwalletUser.VerificationStatuses.NOT_REQUIRED; - -import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.exception.HyperwalletException; -import com.hyperwallet.android.listener.HyperwalletListener; -import com.hyperwallet.android.model.HyperwalletError; -import com.hyperwallet.android.model.HyperwalletErrors; -import com.hyperwallet.android.model.HyperwalletUser; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.Spy; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; -import org.mockito.stubbing.Answer; -import org.robolectric.RobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -@RunWith(RobolectricTestRunner.class) -public class UserRepositoryImplTest { - @Mock - private Hyperwallet mHyperwallet; - @Mock - UserRepository.LoadUserCallback mMockCallback; - @Captor - private ArgumentCaptor mErrorCaptor; - @Captor - private ArgumentCaptor mUserCaptor; - @Rule - public MockitoRule mMockito = MockitoJUnit.rule(); - @Spy - UserRepositoryImpl mUserRepository; - - @Before - public void setup() { - doReturn(mHyperwallet).when(mUserRepository).getHyperwallet(); - } - - @Test - public void testLoadUser_returnsUser() { - HyperwalletUser.Builder builder = new HyperwalletUser.Builder(); - final HyperwalletUser user = builder - .token("usr-f9154016-94e8-4686-a840-075688ac07b5") - .status(PRE_ACTIVATED) - .verificationStatus(NOT_REQUIRED) - .createdOn("2017-10-30T22:15:45") - .clientUserId("123456") - .profileType(INDIVIDUAL) - .firstName("Some") - .lastName("Guy") - .dateOfBirth("1991-01-01") - .email("testUser@hyperwallet.com") - .addressLine1("575 Market Street") - .city("San Francisco") - .stateProvince("CA") - .country("US") - .postalCode("94105") - .language("en") - .programToken("prg-83836cdf-2ce2-4696-8bc5-f1b86077238c") - .build(); - - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[0]; - listener.onSuccess(user); - return listener; - } - }).when(mHyperwallet).getUser(ArgumentMatchers.>any()); - - mUserRepository.loadUser(mMockCallback); - - verify(mMockCallback).onUserLoaded(mUserCaptor.capture()); - verify(mMockCallback, never()).onError(any(HyperwalletErrors.class)); - - HyperwalletUser resultUser = mUserCaptor.getValue(); - assertThat(resultUser.getToken(), is("usr-f9154016-94e8-4686-a840-075688ac07b5")); - assertThat(resultUser.getStatus(), is(PRE_ACTIVATED)); - assertThat(resultUser.getVerificationStatus(), is(NOT_REQUIRED)); - assertThat(resultUser.getCreatedOn(), is("2017-10-30T22:15:45")); - assertThat(resultUser.getClientUserId(), is("123456")); - assertThat(resultUser.getProfileType(), is(INDIVIDUAL)); - assertThat(resultUser.getFirstName(), is("Some")); - assertThat(resultUser.getLastName(), is("Guy")); - assertThat(resultUser.getDateOfBirth(), is("1991-01-01")); - assertThat(resultUser.getEmail(), is("testUser@hyperwallet.com")); - assertThat(resultUser.getAddressLine1(), is("575 Market Street")); - assertThat(resultUser.getCity(), is("San Francisco")); - assertThat(resultUser.getStateProvince(), is("CA")); - assertThat(resultUser.getCountry(), is("US")); - assertThat(resultUser.getPostalCode(), is("94105")); - assertThat(resultUser.getLanguage(), is("en")); - assertThat(resultUser.getProgramToken(), is("prg-83836cdf-2ce2-4696-8bc5-f1b86077238c")); - } - - @Test - public void testLoadUser_returnsNoUser() { - - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[0]; - listener.onSuccess(null); - return listener; - } - }).when(mHyperwallet).getUser(ArgumentMatchers.>any()); - - mUserRepository.loadUser(mMockCallback); - - verify(mMockCallback).onUserLoaded(mUserCaptor.capture()); - verify(mMockCallback, never()).onError(any(HyperwalletErrors.class)); - - HyperwalletUser user = mUserCaptor.getValue(); - assertThat(user, is(nullValue())); - } - - - @Test - public void testLoadUser_withError() { - - final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); - - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[0]; - List errorList = new ArrayList<>(); - errorList.add(error); - HyperwalletErrors errors = new HyperwalletErrors(errorList); - listener.onFailure(new HyperwalletException(errors)); - return listener; - } - }).when(mHyperwallet).getUser(ArgumentMatchers.>any()); - - mUserRepository.loadUser(mMockCallback); - - verify(mMockCallback, never()).onUserLoaded(ArgumentMatchers.any()); - verify(mMockCallback).onError(mErrorCaptor.capture()); - - assertThat(mErrorCaptor.getValue().getErrors(), hasItem(error)); - } - - @Test - public void testRefreshUser_verifyHyperwalletCallGetUser() { - HyperwalletUser.Builder builder = new HyperwalletUser.Builder(); - final HyperwalletUser user = builder - .token("usr-f9154016-94e8-4686-a840-075688ac07b5") - .profileType(INDIVIDUAL) - .build(); - - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[0]; - listener.onSuccess(user); - return listener; - } - }).when(mHyperwallet).getUser(ArgumentMatchers.>any()); - - mUserRepository.loadUser(mMockCallback); - - verify(mHyperwallet).getUser(ArgumentMatchers.>any()); - - mUserRepository.loadUser(mMockCallback); - verify(mHyperwallet).getUser(ArgumentMatchers.>any()); - - mUserRepository.refreshUser(); - mUserRepository.loadUser(mMockCallback); - verify(mHyperwallet, times(2)).getUser(ArgumentMatchers.>any()); - - } -} diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepository.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepository.java deleted file mode 100644 index 902a8d13b..000000000 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepository.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.repository; - -import androidx.annotation.NonNull; - -import com.hyperwallet.android.model.HyperwalletErrors; -import com.hyperwallet.android.model.HyperwalletUser; - -/** - * User Repository Contract - */ -public interface UserRepository { - /** - * Load user information - * - * @param callback @see {@link UserRepository.LoadUserCallback} - */ - void loadUser(@NonNull final LoadUserCallback callback); - - /** - * Set user to null - */ - void refreshUser(); - - /** - * Callback interface that responses to action when invoked to - * Load User information - *

- * When User is properly loaded - * {@link UserRepository.LoadUserCallback#onUserLoaded(HyperwalletUser)} - * is invoked otherwise {@link UserRepository.LoadUserCallback#onError(HyperwalletErrors)} - * is called to further log or show error information - */ - interface LoadUserCallback { - - void onUserLoaded(@NonNull final HyperwalletUser user); - - void onError(@NonNull final HyperwalletErrors errors); - } -} diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepositoryImpl.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepositoryImpl.java deleted file mode 100644 index 561d4cf85..000000000 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/repository/UserRepositoryImpl.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.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.HyperwalletUser; - -public class UserRepositoryImpl implements UserRepository { - - private Handler mHandler = new Handler(); - private HyperwalletUser mUser; - - @VisibleForTesting - Hyperwallet getHyperwallet() { - return Hyperwallet.getDefault(); - } - - @Override - public void loadUser(@NonNull final LoadUserCallback callback) { - if (mUser == null) { - getHyperwallet().getUser(new HyperwalletListener() { - @Override - public void onSuccess(@Nullable HyperwalletUser result) { - mUser = result; - callback.onUserLoaded(mUser); - } - - @Override - public void onFailure(HyperwalletException exception) { - callback.onError(exception.getHyperwalletErrors()); - } - - @Override - public Handler getHandler() { - return mHandler; - } - }); - } else { - callback.onUserLoaded(mUser); - } - } - - @Override - public void refreshUser() { - mUser = null; - } -} diff --git a/transfermethodui/src/test/resources/user_business_response.json b/transfermethodui/src/test/resources/user_business_response.json index 5ba6c60e2..03724745b 100644 --- a/transfermethodui/src/test/resources/user_business_response.json +++ b/transfermethodui/src/test/resources/user_business_response.json @@ -28,7 +28,7 @@ "addressLine2": "second floor", "city": "Burnaby", "stateProvince": "XZ", - "country": "CA", + "country": "US", "postalCode": "v5z3a2", "language": "en", "timeZone": "GMT", From 663addc0d9a9aa98d8429013ae3085d2af611f07 Mon Sep 17 00:00:00 2001 From: Flavio Mattos Date: Mon, 22 Jul 2019 16:36:08 -0700 Subject: [PATCH 030/177] update release version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bc5d01c1d..7a18eb245 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ allprojects { } - project.version = "1.0.0-beta03" + project.version = "1.0.0-beta04-SNAPSHOT" } From dacec28885a0014a460433b016bd6aa4fc45a6a9 Mon Sep 17 00:00:00 2001 From: Peter Joseph Olamit Date: Tue, 23 Jul 2019 13:39:54 -0700 Subject: [PATCH 031/177] HW-53911 sts model update on ui (#76) --- build.gradle | 2 +- receiptui/build.gradle | 1 + receiptui/config/jacoco-settings.gradle | 1 + .../ListPrepaidCardReceiptViewModel.java | 2 +- .../HyperwalletExternalResourceManager.java | 2 +- .../ListPrepaidCardReceiptViewModelTest.java | 50 ++++++++++ .../ListUserReceiptViewModelTest.java | 48 ++++++++++ .../viewmodel/ReceiptDetailViewModelTest.java | 92 +++++++++++++++++++ .../repository/TransferMethodRepository.java | 4 +- .../TransferMethodRepositoryImpl.java | 16 ++-- .../TransferMethodRepositoryImplTest.java | 68 +++++++------- .../ListTransferMethodTest.java | 10 +- ...perwalletTransferMethodLocalBroadcast.java | 6 +- .../view/ListTransferMethodContract.java | 4 +- .../view/ListTransferMethodFragment.java | 4 +- .../view/ListTransferMethodPresenter.java | 4 +- .../ListTransferMethodPresenterTest.java | 23 ++--- 17 files changed, 267 insertions(+), 70 deletions(-) rename receiptui/src/test/java/com/hyperwallet/android/ui/{transfermethod => receipt}/rule/HyperwalletExternalResourceManager.java (97%) create mode 100644 receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModelTest.java create mode 100644 receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModelTest.java create mode 100644 receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModelTest.java diff --git a/build.gradle b/build.gradle index 7a18eb245..b411ad0ba 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ subprojects { targetVersion = 28 codeVersion = 1 - hyperwalletCoreVersion = '1.0.0-beta03' + hyperwalletCoreVersion = '1.0.0-beta04-SNAPSHOT' // androidMaterialVersion = '1.0.0' appcompatVersion = '1.0.2' diff --git a/receiptui/build.gradle b/receiptui/build.gradle index 081d29e7f..d24766afc 100644 --- a/receiptui/build.gradle +++ b/receiptui/build.gradle @@ -16,6 +16,7 @@ dependencies { implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion" implementation "androidx.paging:paging-runtime:$pagingRuntimeVersion" + testImplementation "org.robolectric:robolectric:$robolectricVersion" androidTestImplementation "androidx.test:rules:$testRulesVersion" androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" diff --git a/receiptui/config/jacoco-settings.gradle b/receiptui/config/jacoco-settings.gradle index 7dbc462e6..c293d9a13 100644 --- a/receiptui/config/jacoco-settings.gradle +++ b/receiptui/config/jacoco-settings.gradle @@ -21,6 +21,7 @@ android { } def fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/receipt/HyperwalletReceiptUi.*', '**/com/hyperwallet/android/ui/receipt/view/*.*', '**/com/hyperwallet/android/ui/receipt/viewmodel/*.*' ] diff --git a/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java index 0b72276be..edda03cc7 100644 --- a/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java +++ b/receiptui/src/main/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModel.java @@ -120,7 +120,7 @@ public ListPrepaidCardReceiptViewModelFactory(@NonNull final PrepaidCardReceiptR @NonNull @Override public T create(@NonNull final Class modelClass) { - if (modelClass.isAssignableFrom(ListUserReceiptViewModel.class)) { + if (modelClass.isAssignableFrom(ListPrepaidCardReceiptViewModel.class)) { return (T) new ListPrepaidCardReceiptViewModel(mPrepaidCardReceiptRepository); } throw new IllegalArgumentException( diff --git a/receiptui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java similarity index 97% rename from receiptui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java rename to receiptui/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java index e7ac68fac..abc9bf5da 100644 --- a/receiptui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java +++ b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.transfermethod.rule; +package com.hyperwallet.android.ui.receipt.rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; diff --git a/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModelTest.java b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModelTest.java new file mode 100644 index 000000000..c23d3d712 --- /dev/null +++ b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ListPrepaidCardReceiptViewModelTest.java @@ -0,0 +1,50 @@ +package com.hyperwallet.android.ui.receipt.viewmodel; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.hyperwallet.android.ui.receipt.repository.PrepaidCardReceiptRepository; +import com.hyperwallet.android.ui.receipt.repository.PrepaidCardReceiptRepositoryImpl; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ListPrepaidCardReceiptViewModelTest { + + private ReceiptViewModel mReceiptViewModelToTest; + + @Before + public void initializedViewModel() { + PrepaidCardReceiptRepository prepaidCardReceiptRepository = new PrepaidCardReceiptRepositoryImpl( + "trm-ppc-token"); + ListPrepaidCardReceiptViewModel.ListPrepaidCardReceiptViewModelFactory factory = + new ListPrepaidCardReceiptViewModel.ListPrepaidCardReceiptViewModelFactory( + prepaidCardReceiptRepository); + + mReceiptViewModelToTest = factory.create(ReceiptViewModel.class); + } + + @Test + public void testIsLoadingData_returnsLiveData() { + assertThat(mReceiptViewModelToTest.isLoadingData(), is(notNullValue())); + } + + @Test + public void testGetReceiptErrors_returnsLiveData() { + assertThat(mReceiptViewModelToTest.getReceiptErrors(), is(notNullValue())); + } + + @Test + public void testGetReceiptList_returnsLiveData() { + assertThat(mReceiptViewModelToTest.getReceiptList(), is(notNullValue())); + } + + @Test + public void testGetDetailNavigation_returnsLiveData() { + assertThat(mReceiptViewModelToTest.getDetailNavigation(), is(notNullValue())); + } +} \ No newline at end of file diff --git a/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModelTest.java b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModelTest.java new file mode 100644 index 000000000..e9a1f8a12 --- /dev/null +++ b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ListUserReceiptViewModelTest.java @@ -0,0 +1,48 @@ +package com.hyperwallet.android.ui.receipt.viewmodel; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.hyperwallet.android.ui.receipt.repository.UserReceiptRepository; +import com.hyperwallet.android.ui.receipt.repository.UserReceiptRepositoryImpl; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ListUserReceiptViewModelTest { + + private ReceiptViewModel mReceiptViewModelToTest; + + @Before + public void initializedViewModel() { + UserReceiptRepository userReceiptRepository = new UserReceiptRepositoryImpl(); + ListUserReceiptViewModel.ListReceiptViewModelFactory factory = + new ListUserReceiptViewModel.ListReceiptViewModelFactory(userReceiptRepository); + + mReceiptViewModelToTest = factory.create(ReceiptViewModel.class); + } + + @Test + public void testIsLoadingData_returnsLiveData() { + assertThat(mReceiptViewModelToTest.isLoadingData(), is(notNullValue())); + } + + @Test + public void testGetReceiptErrors_returnsLiveData() { + assertThat(mReceiptViewModelToTest.getReceiptErrors(), is(notNullValue())); + } + + @Test + public void testGetReceiptList_returnsLiveData() { + assertThat(mReceiptViewModelToTest.getReceiptList(), is(notNullValue())); + } + + @Test + public void testGetDetailNavigation_returnsLiveData() { + assertThat(mReceiptViewModelToTest.getDetailNavigation(), is(notNullValue())); + } +} \ No newline at end of file diff --git a/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModelTest.java b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModelTest.java new file mode 100644 index 000000000..0f965e28c --- /dev/null +++ b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModelTest.java @@ -0,0 +1,92 @@ +package com.hyperwallet.android.ui.receipt.viewmodel; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import static com.hyperwallet.android.ui.receipt.view.ReceiptDetailActivity.EXTRA_RECEIPT; + +import android.content.Intent; + +import androidx.lifecycle.ViewModelProviders; + +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.model.paging.HyperwalletPageList; +import com.hyperwallet.android.model.receipt.Receipt; +import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.receipt.view.ReceiptDetailActivity; + +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ReceiptDetailViewModelTest { + + @Rule + public HyperwalletExternalResourceManager mExternalResourceManager = new HyperwalletExternalResourceManager(); + + private Intent mIntent; + private Receipt mReceipt; + private HyperwalletPageList mReceiptList; + + @Before + public void initialize() throws JSONException, HyperwalletException { + String json = mExternalResourceManager.getResourceContent("prepaid_card_receipt_list_response.json"); + JSONObject jsonObject = new JSONObject(json); + mReceiptList = new HyperwalletPageList<>(jsonObject, Receipt.class); + + mIntent = new Intent(); + mReceipt = mReceiptList.getDataList().get(0); + mIntent.putExtra(EXTRA_RECEIPT, mReceipt); + } + + @Test + public void testReceiptDetailViewModel_isInitialized() { + + ReceiptDetailActivity activity = Robolectric.buildActivity(ReceiptDetailActivity.class, mIntent).setup().get(); + + ReceiptDetailViewModel model = ViewModelProviders.of(activity).get(ReceiptDetailViewModel.class); + + assertThat(model, is(notNullValue())); + } + + @Test + public void testReceiptDetailViewModel_verifyDefaultValues() { + ReceiptDetailActivity activity = Robolectric.buildActivity(ReceiptDetailActivity.class, mIntent).setup().get(); + + ReceiptDetailViewModel model = ViewModelProviders.of(activity).get(ReceiptDetailViewModel.class); + + assertThat(model, is(notNullValue())); + assertThat(model.getReceipt(), is(notNullValue())); + assertThat(model.getReceipt(), is(mReceipt)); + assertThat(model.getReceipt().getDetails(), is(mReceipt.getDetails())); + } + + @Test + public void testReceiptDetailViewModel_verifyReceiptSet() { + ReceiptDetailActivity activity = Robolectric.buildActivity(ReceiptDetailActivity.class, mIntent).setup().get(); + + ReceiptDetailViewModel model = ViewModelProviders.of(activity).get(ReceiptDetailViewModel.class); + + // default receipt + assertThat(model, is(notNullValue())); + assertThat(model.getReceipt(), is(mReceipt)); + assertThat(model.getReceipt().getDetails(), is(mReceipt.getDetails())); + + // prepare and set new receipt + Receipt newReceipt = mReceiptList.getDataList().get(1); + model.setReceipt(newReceipt); + + // new receipt is now latest value of model.getReceipt + assertThat(model.getReceipt(), is(not(mReceipt))); + assertThat(model.getReceipt(), is(newReceipt)); + assertThat(model.getReceipt().getDetails(), is(newReceipt.getDetails())); + } +} \ No newline at end of file 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 dce02d886..93e057de1 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 @@ -19,7 +19,7 @@ import androidx.annotation.NonNull; import com.hyperwallet.android.model.HyperwalletErrors; -import com.hyperwallet.android.model.HyperwalletStatusTransition; +import com.hyperwallet.android.model.StatusTransition; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import java.util.List; @@ -87,7 +87,7 @@ interface LoadTransferMethodListCallback { */ interface DeactivateTransferMethodCallback { - void onTransferMethodDeactivated(final @NonNull HyperwalletStatusTransition statusTransition); + void onTransferMethodDeactivated(final @NonNull StatusTransition statusTransition); void onError(HyperwalletErrors errors); } 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 69f450ec2..a7596bce0 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 @@ -16,7 +16,7 @@ */ package com.hyperwallet.android.ui.transfermethod.repository; -import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.ACTIVATED; +import static com.hyperwallet.android.model.StatusTransition.StatusDefinition.ACTIVATED; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TOKEN; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TYPE; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_ACCOUNT; @@ -33,7 +33,7 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.exception.HyperwalletException; import com.hyperwallet.android.listener.HyperwalletListener; -import com.hyperwallet.android.model.HyperwalletStatusTransition; +import com.hyperwallet.android.model.StatusTransition; import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount; import com.hyperwallet.android.model.transfermethod.HyperwalletBankCard; @@ -114,9 +114,9 @@ public void deactivateTransferMethod(@NonNull final HyperwalletTransferMethod tr private void deactivateBankAccount(@NonNull final HyperwalletTransferMethod transferMethod, @NonNull final DeactivateTransferMethodCallback callback) { getHyperwallet().deactivateBankAccount(transferMethod.getField(TOKEN), null, - new HyperwalletListener() { + new HyperwalletListener() { @Override - public void onSuccess(@Nullable HyperwalletStatusTransition result) { + public void onSuccess(@Nullable StatusTransition result) { callback.onTransferMethodDeactivated(result); } @@ -135,9 +135,9 @@ public Handler getHandler() { private void deactivateBankCardAccount(@NonNull final HyperwalletTransferMethod transferMethod, @NonNull final DeactivateTransferMethodCallback callback) { getHyperwallet().deactivateBankCard(transferMethod.getField(TOKEN), null, - new HyperwalletListener() { + new HyperwalletListener() { @Override - public void onSuccess(@Nullable HyperwalletStatusTransition result) { + public void onSuccess(@Nullable StatusTransition result) { callback.onTransferMethodDeactivated(result); } @@ -156,9 +156,9 @@ public Handler getHandler() { private void deactivatePayPalAccount(@NonNull final HyperwalletTransferMethod transferMethod, @NonNull final DeactivateTransferMethodCallback callback) { getHyperwallet().deactivatePayPalAccount(transferMethod.getField(TOKEN), null, - new HyperwalletListener() { + new HyperwalletListener() { @Override - public void onSuccess(@Nullable HyperwalletStatusTransition result) { + public void onSuccess(@Nullable StatusTransition result) { callback.onTransferMethodDeactivated(result); } diff --git a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java index 0e7b396c0..6d7f91f17 100644 --- a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java @@ -13,8 +13,8 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.ACTIVATED; -import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.DE_ACTIVATED; +import static com.hyperwallet.android.model.StatusTransition.StatusDefinition.ACTIVATED; +import static com.hyperwallet.android.model.StatusTransition.StatusDefinition.DE_ACTIVATED; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.BANK_ACCOUNT_ID; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.BANK_NAME; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.STATUS; @@ -28,7 +28,7 @@ import com.hyperwallet.android.listener.HyperwalletListener; import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.model.HyperwalletErrors; -import com.hyperwallet.android.model.HyperwalletStatusTransition; +import com.hyperwallet.android.model.StatusTransition; import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount; import com.hyperwallet.android.model.transfermethod.HyperwalletBankCard; @@ -81,7 +81,7 @@ public class TransferMethodRepositoryImplTest { @Captor private ArgumentCaptor mPayPalAccountArgumentCaptor; @Captor - private ArgumentCaptor mStatusTransitionArgumentCaptor; + private ArgumentCaptor mStatusTransitionArgumentCaptor; @Captor private ArgumentCaptor> mListTransferMethodCaptor; @@ -162,18 +162,19 @@ public void testDeactivateTransferMethod_bankAccountWithSuccess() { .Builder("CA", "CAD", "3423423432") .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56") .build(); - bankAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + bankAccount.setField(STATUS, StatusTransition.StatusDefinition.ACTIVATED); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) { - HyperwalletStatusTransition statusTransition = new HyperwalletStatusTransition(DE_ACTIVATED); - statusTransition.setNotes("Closing this account."); + StatusTransition statusTransition = new StatusTransition.Builder() + .transition(DE_ACTIVATED) + .notes("Closing this account.").build(); HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; listener.onSuccess(statusTransition); return listener; } }).when(mHyperwallet).deactivateBankAccount(anyString(), ArgumentMatchers.isNull(), - ArgumentMatchers.>any()); + ArgumentMatchers.>any()); // test mTransferMethodRepository.deactivateTransferMethod(bankAccount, mDeactivateTransferMethodCallback); @@ -182,7 +183,7 @@ public Object answer(InvocationOnMock invocation) { mStatusTransitionArgumentCaptor.capture()); verify(mDeactivateTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); - HyperwalletStatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); + StatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); assertThat(statusTransition, is(notNullValue())); assertThat(statusTransition.getTransition(), is(DE_ACTIVATED)); assertThat(statusTransition.getNotes(), is("Closing this account.")); @@ -194,7 +195,7 @@ public void testDeactivateTransferMethod_bankAccountWithError() { .Builder("CA", "CAD", "3423423432") .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56") .build(); - bankAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + bankAccount.setField(STATUS, StatusTransition.StatusDefinition.ACTIVATED); final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); doAnswer(new Answer() { @Override @@ -207,13 +208,13 @@ public Object answer(InvocationOnMock invocation) { return listener; } }).when(mHyperwallet).deactivateBankAccount(anyString(), ArgumentMatchers.isNull(), - ArgumentMatchers.>any()); + ArgumentMatchers.>any()); // test mTransferMethodRepository.deactivateTransferMethod(bankAccount, mDeactivateTransferMethodCallback); verify(mDeactivateTransferMethodCallback, never()).onTransferMethodDeactivated( - any(HyperwalletStatusTransition.class)); + any(StatusTransition.class)); verify(mDeactivateTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); @@ -225,18 +226,19 @@ public void testDeactivateTransferMethod_bankCardWithSuccess() { .Builder("CA", "CAD", "1232345456784", "2019-05", "234") .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56") .build(); - bankCard.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + bankCard.setField(STATUS, StatusTransition.StatusDefinition.ACTIVATED); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) { - HyperwalletStatusTransition statusTransition = new HyperwalletStatusTransition(DE_ACTIVATED); - statusTransition.setNotes("Closing this account."); + StatusTransition statusTransition = new StatusTransition.Builder() + .transition(DE_ACTIVATED) + .notes("Closing this account.").build(); HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; listener.onSuccess(statusTransition); return listener; } }).when(mHyperwallet).deactivateBankCard(anyString(), ArgumentMatchers.isNull(), - ArgumentMatchers.>any()); + ArgumentMatchers.>any()); // test mTransferMethodRepository.deactivateTransferMethod(bankCard, mDeactivateTransferMethodCallback); @@ -245,7 +247,7 @@ public Object answer(InvocationOnMock invocation) { mStatusTransitionArgumentCaptor.capture()); verify(mDeactivateTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); - HyperwalletStatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); + StatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); assertThat(statusTransition, is(notNullValue())); assertThat(statusTransition.getTransition(), is(DE_ACTIVATED)); assertThat(statusTransition.getNotes(), is("Closing this account.")); @@ -257,7 +259,7 @@ public void testDeactivateTransferMethod_bankCardWithError() { .Builder("CA", "CAD", "1232345456784", "2019-05", "234") .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56") .build(); - bankCard.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + bankCard.setField(STATUS, StatusTransition.StatusDefinition.ACTIVATED); final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); doAnswer(new Answer() { @Override @@ -270,13 +272,13 @@ public Object answer(InvocationOnMock invocation) { return listener; } }).when(mHyperwallet).deactivateBankCard(anyString(), ArgumentMatchers.isNull(), - ArgumentMatchers.>any()); + ArgumentMatchers.>any()); // test mTransferMethodRepository.deactivateTransferMethod(bankCard, mDeactivateTransferMethodCallback); verify(mDeactivateTransferMethodCallback, never()).onTransferMethodDeactivated( - any(HyperwalletStatusTransition.class)); + any(StatusTransition.class)); verify(mDeactivateTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); @@ -289,14 +291,15 @@ public void testDeactivateTransferMethod_payPalAccountWithSuccess() { doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) { - HyperwalletStatusTransition statusTransition = new HyperwalletStatusTransition(DE_ACTIVATED); - statusTransition.setNotes("Closing this account."); + StatusTransition statusTransition = new StatusTransition.Builder() + .transition(DE_ACTIVATED) + .notes("Closing this account.").build(); HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; listener.onSuccess(statusTransition); return listener; } }).when(mHyperwallet).deactivatePayPalAccount(anyString(), ArgumentMatchers.isNull(), - ArgumentMatchers.>any()); + ArgumentMatchers.>any()); // test mTransferMethodRepository.deactivateTransferMethod(payPalAccount, mDeactivateTransferMethodCallback); @@ -305,7 +308,7 @@ public Object answer(InvocationOnMock invocation) { mStatusTransitionArgumentCaptor.capture()); verify(mDeactivateTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); - HyperwalletStatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); + StatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); assertThat(statusTransition, is(notNullValue())); assertThat(statusTransition.getTransition(), is(DE_ACTIVATED)); assertThat(statusTransition.getNotes(), is("Closing this account.")); @@ -315,7 +318,7 @@ public Object answer(InvocationOnMock invocation) { public void testDeactivateTransferMethod_payPalAccountWithError() { PayPalAccount payPalAccount = new PayPalAccount.Builder("US", "US", "jsmith4@hyperwallet.com") .token("trm-854c4ec1-9161-49d6-92e2-b8d15aa4bf56").build(); - payPalAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + payPalAccount.setField(STATUS, StatusTransition.StatusDefinition.ACTIVATED); final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); doAnswer(new Answer() { @Override @@ -328,13 +331,13 @@ public Object answer(InvocationOnMock invocation) { return listener; } }).when(mHyperwallet).deactivatePayPalAccount(anyString(), ArgumentMatchers.isNull(), - ArgumentMatchers.>any()); + ArgumentMatchers.>any()); // test mTransferMethodRepository.deactivateTransferMethod(payPalAccount, mDeactivateTransferMethodCallback); verify(mDeactivateTransferMethodCallback, never()).onTransferMethodDeactivated( - any(HyperwalletStatusTransition.class)); + any(StatusTransition.class)); verify(mDeactivateTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); @@ -603,18 +606,19 @@ public void testDeactivateTransferMethod_wireAccountWithSuccess() { .transferMethodType(HyperwalletTransferMethod.TransferMethodTypes.WIRE_ACCOUNT) .token("trm-123") .build(); - bankAccount.setField(STATUS, HyperwalletStatusTransition.StatusDefinition.ACTIVATED); + bankAccount.setField(STATUS, StatusTransition.StatusDefinition.ACTIVATED); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) { - HyperwalletStatusTransition statusTransition = new HyperwalletStatusTransition(DE_ACTIVATED); - statusTransition.setNotes("Closing this account."); + StatusTransition statusTransition = new StatusTransition.Builder() + .transition(DE_ACTIVATED) + .notes("Closing this account.").build(); HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[2]; listener.onSuccess(statusTransition); return listener; } }).when(mHyperwallet).deactivateBankAccount(anyString(), ArgumentMatchers.isNull(), - ArgumentMatchers.>any()); + ArgumentMatchers.>any()); // test mTransferMethodRepository.deactivateTransferMethod(bankAccount, mDeactivateTransferMethodCallback); @@ -623,7 +627,7 @@ public Object answer(InvocationOnMock invocation) { mStatusTransitionArgumentCaptor.capture()); verify(mDeactivateTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); - HyperwalletStatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); + StatusTransition statusTransition = mStatusTransitionArgumentCaptor.getValue(); assertThat(statusTransition, is(notNullValue())); assertThat(statusTransition.getTransition(), is(DE_ACTIVATED)); assertThat(statusTransition.getNotes(), is("Closing this account.")); diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java index d53840652..b45308b86 100644 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java @@ -20,7 +20,7 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.concurrent.TimeUnit.SECONDS; -import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.DE_ACTIVATED; +import static com.hyperwallet.android.model.StatusTransition.StatusDefinition.DE_ACTIVATED; import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.atPosition; import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withDrawable; @@ -38,7 +38,7 @@ import androidx.test.rule.ActivityTestRule; import com.hyperwallet.android.Hyperwallet; -import com.hyperwallet.android.model.HyperwalletStatusTransition; +import com.hyperwallet.android.model.StatusTransition; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; @@ -222,7 +222,7 @@ public void testListTransferMethod_removeBankAccount() throws InterruptedExcepti public void onReceive(Context context, Intent intent) { gate.countDown(); - HyperwalletStatusTransition statusTransition = intent.getParcelableExtra( + StatusTransition statusTransition = intent.getParcelableExtra( "hyperwallet-local-broadcast-payload"); assertThat("Transition is not valid", statusTransition.getTransition(), is(DE_ACTIVATED)); } @@ -298,7 +298,7 @@ public void testListTransferMethod_removeBankCard() throws InterruptedException public void onReceive(Context context, Intent intent) { gate.countDown(); - HyperwalletStatusTransition statusTransition = intent.getParcelableExtra( + StatusTransition statusTransition = intent.getParcelableExtra( "hyperwallet-local-broadcast-payload"); assertThat("Transition is not valid", statusTransition.getTransition(), is(DE_ACTIVATED)); } @@ -364,7 +364,7 @@ public void testListTransferMethod_removePayPalAccount() throws InterruptedExcep public void onReceive(Context context, Intent intent) { gate.countDown(); - HyperwalletStatusTransition statusTransition = intent.getParcelableExtra( + StatusTransition statusTransition = intent.getParcelableExtra( "hyperwallet-local-broadcast-payload"); assertThat("Transition is not valid", statusTransition.getTransition(), is(DE_ACTIVATED)); } diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodLocalBroadcast.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodLocalBroadcast.java index e10b351ef..29e21765e 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodLocalBroadcast.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodLocalBroadcast.java @@ -25,7 +25,7 @@ import androidx.annotation.NonNull; import androidx.annotation.StringDef; -import com.hyperwallet.android.model.HyperwalletStatusTransition; +import com.hyperwallet.android.model.StatusTransition; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import java.lang.annotation.Retention; @@ -42,8 +42,8 @@ public static Intent createBroadcastIntentTransferMethodAdded( } public static Intent createBroadcastIntentTransferMethodDeactivated( - @NonNull final HyperwalletStatusTransition hyperwalletStatusTransition) { - return createBroadcastIntent(hyperwalletStatusTransition, + @NonNull final StatusTransition StatusTransition) { + return createBroadcastIntent(StatusTransition, ACTION_HYPERWALLET_TRANSFER_METHOD_DEACTIVATED); } diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodContract.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodContract.java index 7727cd404..275346995 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodContract.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/ListTransferMethodContract.java @@ -19,7 +19,7 @@ import androidx.annotation.NonNull; import com.hyperwallet.android.model.HyperwalletError; -import com.hyperwallet.android.model.HyperwalletStatusTransition; +import com.hyperwallet.android.model.StatusTransition; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import java.util.List; @@ -30,7 +30,7 @@ interface View { void displayTransferMethods(@NonNull final List transferMethodList); - void notifyTransferMethodDeactivated(@NonNull final HyperwalletStatusTransition statusTransition); + void notifyTransferMethodDeactivated(@NonNull final StatusTransition statusTransition); void showErrorListTransferMethods(@NonNull final List errors); 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 77236a1a3..a1fb9d213 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 @@ -44,7 +44,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.hyperwallet.android.model.HyperwalletError; -import com.hyperwallet.android.model.HyperwalletStatusTransition; +import com.hyperwallet.android.model.StatusTransition; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.common.view.HorizontalDividerItemDecorator; @@ -223,7 +223,7 @@ public void displayTransferMethods(@Nullable final ListanyList()); verify(mView, never()).showErrorListTransferMethods(ArgumentMatchers.anyList()); - verify(mView, never()).notifyTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); + verify(mView, never()).notifyTransferMethodDeactivated(any(StatusTransition.class)); verify(mView, never()).initiateAddTransferMethodFlow(); verify(mView, never()).initiateAddTransferMethodFlowResult(); verify(mView, atLeastOnce()).displayTransferMethods(mListArgumentTransferMethodCaptor.capture()); @@ -144,7 +145,7 @@ public Object answer(InvocationOnMock invocation) { verify(mView, never()).showErrorDeactivateTransferMethod(ArgumentMatchers.anyList()); verify(mView, never()).showErrorListTransferMethods(ArgumentMatchers.anyList()); - verify(mView, never()).notifyTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); + verify(mView, never()).notifyTransferMethodDeactivated(any(StatusTransition.class)); verify(mView, never()).initiateAddTransferMethodFlow(); verify(mView, never()).initiateAddTransferMethodFlowResult(); verify(mView, never()).displayTransferMethods(mListArgumentTransferMethodCaptor.capture()); @@ -177,7 +178,7 @@ public Object answer(InvocationOnMock invocation) { any(TransferMethodRepository.LoadTransferMethodCallback.class)); verify(mView, never()).showErrorDeactivateTransferMethod(ArgumentMatchers.anyList()); verify(mView, never()).showErrorListTransferMethods(ArgumentMatchers.anyList()); - verify(mView, never()).notifyTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); + verify(mView, never()).notifyTransferMethodDeactivated(any(StatusTransition.class)); verify(mView, never()).initiateAddTransferMethodFlow(); verify(mView, never()).initiateAddTransferMethodFlowResult(); verify(mView, atLeastOnce()).displayTransferMethods(mListArgumentTransferMethodCaptor.capture()); @@ -212,7 +213,7 @@ public Object answer(InvocationOnMock invocation) { verify(mTransferMethodRepository, never()).createTransferMethod(any(HyperwalletTransferMethod.class), any(TransferMethodRepository.LoadTransferMethodCallback.class)); verify(mView, never()).displayTransferMethods(ArgumentMatchers.anyList()); - verify(mView, never()).notifyTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); + verify(mView, never()).notifyTransferMethodDeactivated(any(StatusTransition.class)); verify(mView, never()).initiateAddTransferMethodFlow(); verify(mView, never()).initiateAddTransferMethodFlowResult(); verify(mView, atLeastOnce()).showErrorListTransferMethods(mListArgumentErrorCaptor.capture()); @@ -276,7 +277,7 @@ public Object answer(InvocationOnMock invocation) { verify(mView, never()).initiateAddTransferMethodFlowResult(); verify(mView, never()).showErrorDeactivateTransferMethod(ArgumentMatchers.anyList()); verify(mView, never()).showErrorListTransferMethods(ArgumentMatchers.anyList()); - verify(mView, atLeastOnce()).notifyTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); + verify(mView, atLeastOnce()).notifyTransferMethodDeactivated(any(StatusTransition.class)); } @Test @@ -303,7 +304,7 @@ public Object answer(InvocationOnMock invocation) { verify(mView, never()).initiateAddTransferMethodFlowResult(); verify(mView, never()).showErrorDeactivateTransferMethod(ArgumentMatchers.anyList()); verify(mView, never()).showErrorListTransferMethods(ArgumentMatchers.anyList()); - verify(mView, never()).notifyTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); + verify(mView, never()).notifyTransferMethodDeactivated(any(StatusTransition.class)); } @Test @@ -334,7 +335,7 @@ public Object answer(InvocationOnMock invocation) { verify(mView, never()).displayTransferMethods(ArgumentMatchers.anyList()); verify(mView, never()).initiateAddTransferMethodFlow(); verify(mView, never()).initiateAddTransferMethodFlowResult(); - verify(mView, never()).notifyTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); + verify(mView, never()).notifyTransferMethodDeactivated(any(StatusTransition.class)); verify(mView, atLeastOnce()).showErrorDeactivateTransferMethod(mListArgumentErrorCaptor.capture()); List capturedList = mListArgumentErrorCaptor.getValue(); @@ -365,7 +366,7 @@ public Object answer(InvocationOnMock invocation) { verify(mView, never()).displayTransferMethods(ArgumentMatchers.anyList()); verify(mView, never()).initiateAddTransferMethodFlow(); verify(mView, never()).initiateAddTransferMethodFlowResult(); - verify(mView, never()).notifyTransferMethodDeactivated(any(HyperwalletStatusTransition.class)); + verify(mView, never()).notifyTransferMethodDeactivated(any(StatusTransition.class)); verify(mView, never()).showErrorDeactivateTransferMethod(ArgumentMatchers.anyList()); verify(mView, never()).showErrorListTransferMethods(ArgumentMatchers.anyList()); } From 5ecea2384a004e74428b70cbfceab2fe2f35f8df Mon Sep 17 00:00:00 2001 From: vshcherbyna-epam <48257687+vshcherbyna-epam@users.noreply.github.com> Date: Wed, 24 Jul 2019 02:22:44 +0300 Subject: [PATCH 032/177] HW-54791 Create Transfer repository module (#73) --- settings.gradle | 10 ++- transferrepository/.gitignore | 1 + transferrepository/build.gradle | 13 +++ .../config/jacoco-settings.gradle | 79 ++++++++++++++++++ transferrepository/config/lint.xml | 4 + .../src/main/AndroidManifest.xml | 4 + .../HyperwalletExternalResourceManager.java | 72 +++++++++++++++++ transferui/.gitignore | 1 + transferui/build.gradle | 11 +++ transferui/config/jacoco-settings.gradle | 81 +++++++++++++++++++ transferui/config/lint.xml | 7 ++ transferui/proguard-rules.pro | 21 +++++ .../HyperwalletExternalResourceManager.java | 73 +++++++++++++++++ transferui/src/main/AndroidManifest.xml | 2 + .../HyperwalletTransferLocalBroadcast.java | 21 +++++ .../ui/transfer/HyperwalletTransferUi.java | 51 ++++++++++++ 16 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 transferrepository/.gitignore create mode 100644 transferrepository/build.gradle create mode 100644 transferrepository/config/jacoco-settings.gradle create mode 100644 transferrepository/config/lint.xml create mode 100644 transferrepository/src/main/AndroidManifest.xml create mode 100644 transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java create mode 100644 transferui/.gitignore create mode 100644 transferui/build.gradle create mode 100644 transferui/config/jacoco-settings.gradle create mode 100644 transferui/config/lint.xml create mode 100644 transferui/proguard-rules.pro create mode 100644 transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java create mode 100644 transferui/src/main/AndroidManifest.xml create mode 100644 transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferLocalBroadcast.java create mode 100644 transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferUi.java diff --git a/settings.gradle b/settings.gradle index 9058fac39..2dc592721 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,9 @@ -include ':transfermethodui', ':receiptui', ':commonui', ':receiptrepository', ':userrepository', ':transfermethodrepository', ':commonrepository' +include ':commonui', + ':commonrepository', + ':receiptrepository', + ':receiptui', + ':transfermethodrepository', + ':transfermethodui', + ':transferrepository', + ':transferui', + ':userrepository' diff --git a/transferrepository/.gitignore b/transferrepository/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/transferrepository/.gitignore @@ -0,0 +1 @@ +/build diff --git a/transferrepository/build.gradle b/transferrepository/build.gradle new file mode 100644 index 000000000..12fc432a2 --- /dev/null +++ b/transferrepository/build.gradle @@ -0,0 +1,13 @@ +apply from: "$rootProject.projectDir/android-library.gradle" +description = 'Hyperwallet Transfer Repository SDK for Android to integrate with the Hyperwallet Platform' +project.ext { + mavenName = 'Hyperwallet Android Transfer Repository SDK' +} +apply from: "$rootProject.projectDir/publish.gradle" + +dependencies { + + api project(':commonrepository') + + testImplementation "org.robolectric:robolectric:$robolectricVersion" +} \ No newline at end of file diff --git a/transferrepository/config/jacoco-settings.gradle b/transferrepository/config/jacoco-settings.gradle new file mode 100644 index 000000000..bb4ffa228 --- /dev/null +++ b/transferrepository/config/jacoco-settings.gradle @@ -0,0 +1,79 @@ +apply plugin: 'jacoco' + +final def jacocoVersion = "0.8.2" + +jacoco { + toolVersion = jacocoVersion +} + +android { + testOptions { + unitTests { + includeAndroidResources = true + returnDefaultValues = true + } + unitTests.all { + jacoco { + includeNoLocationClasses = true + } + } + } +} + +def fileFilter = ['**/BuildConfig.*' +] + +def debugClassPaths = [ + '**/intermediates/javac/debug/*/classes/**' +] + +final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] + +task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { + + group = 'Reporting' + description = 'Generate Jacoco coverage reports.' + reports { + html { + enabled = true + destination file("$project.buildDir/reports/jacoco") + } + } + + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") +} + +task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { + + group = 'Verification' + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") + + violationRules { + setFailOnViolation(true) + + rule { + element = 'CLASS' + limit { + value = 'COVEREDRATIO' + counter = 'BRANCH' + minimum = 0.65 + } + } + } +} + diff --git a/transferrepository/config/lint.xml b/transferrepository/config/lint.xml new file mode 100644 index 000000000..4eac6b512 --- /dev/null +++ b/transferrepository/config/lint.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/transferrepository/src/main/AndroidManifest.xml b/transferrepository/src/main/AndroidManifest.xml new file mode 100644 index 000000000..2c780ad58 --- /dev/null +++ b/transferrepository/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java b/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java new file mode 100644 index 000000000..d25311f64 --- /dev/null +++ b/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java @@ -0,0 +1,72 @@ +package com.hyperwallet.android.ui.transfer.rule; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class HyperwalletExternalResourceManager extends TestWatcher { + + private static final String EMPTY = ""; + private ClassLoader classLoader; + private Logger logger; + + @Override + protected void starting(Description description) { + super.starting(description); + classLoader = description.getTestClass().getClassLoader(); + logger = Logger.getLogger(description.getTestClass().getName()); + } + + public String getResourceContent(final String resourceName) { + if (resourceName == null) { + throw new IllegalArgumentException("Parameter resourceName cannot be null"); + } + + return getContent(resourceName); + } + + private String getContent(final String resourceName) { + URL resource = classLoader.getResource(resourceName); + InputStream inputStream = null; + Writer writer = new StringWriter(); + String resourceContent = EMPTY; + if (resource != null) { + try { + inputStream = resource.openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + String line = reader.readLine(); + while (line != null) { + writer.write(line); + line = reader.readLine(); + } + resourceContent = writer.toString(); + + } catch (Exception e) { + logger.log(Level.WARNING, "There was an error loading an external resource", e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "There was an error closing input stream", e); + } + try { + writer.close(); + } catch (IOException e) { + logger.log(Level.SEVERE, "There was an error closing writer", e); + } + } + } + return resourceContent; + } +} diff --git a/transferui/.gitignore b/transferui/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/transferui/.gitignore @@ -0,0 +1 @@ +/build diff --git a/transferui/build.gradle b/transferui/build.gradle new file mode 100644 index 000000000..4b5738db4 --- /dev/null +++ b/transferui/build.gradle @@ -0,0 +1,11 @@ +apply from: "$rootProject.projectDir/android-library.gradle" +description = 'Hyperwallet Transfer UI SDK for Android to integrate with the Hyperwallet Platform' +project.ext { + mavenName = 'Hyperwallet Android Transfer UI SDK' +} +apply from: "$rootProject.projectDir/publish.gradle" + +dependencies { + implementation project(":transferrepository") + implementation project(":transfermethodrepository") +} \ No newline at end of file diff --git a/transferui/config/jacoco-settings.gradle b/transferui/config/jacoco-settings.gradle new file mode 100644 index 000000000..f8110818c --- /dev/null +++ b/transferui/config/jacoco-settings.gradle @@ -0,0 +1,81 @@ +apply plugin: 'jacoco' + +final def jacocoVersion = "0.8.2" + +jacoco { + toolVersion = jacocoVersion +} + +android { + testOptions { + unitTests { + includeAndroidResources = true + returnDefaultValues = true + } + unitTests.all { + jacoco { + includeNoLocationClasses = true + } + } + } +} + +def fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/transfer/view/*.*', + '**/com/hyperwallet/android/ui/transfer/viewmodel/*.*' +] + +def debugClassPaths = [ + '**/intermediates/javac/debug/*/classes/**' +] + +final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] + +task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { + + group = 'Reporting' + description = 'Generate Jacoco coverage reports.' + reports { + html { + enabled = true + destination file("$project.buildDir/reports/jacoco") + } + } + + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") +} + +task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { + + group = 'Verification' + classDirectories = fileTree( + dir: "${buildDir}", + includes: debugClassPaths, + excludes: fileFilter + ) + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") + + violationRules { + setFailOnViolation(true) + + rule { + element = 'CLASS' + limit { + value = 'COVEREDRATIO' + counter = 'BRANCH' + minimum = 0.65 + } + } + } +} + diff --git a/transferui/config/lint.xml b/transferui/config/lint.xml new file mode 100644 index 000000000..3c83d4bb5 --- /dev/null +++ b/transferui/config/lint.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/transferui/proguard-rules.pro b/transferui/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/transferui/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java b/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java new file mode 100644 index 000000000..b5a463e9c --- /dev/null +++ b/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java @@ -0,0 +1,73 @@ +package com.hyperwallet.android.ui.transfer.rule; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class HyperwalletExternalResourceManager extends TestWatcher { + + private static final String EMPTY = ""; + private ClassLoader classLoader; + private Logger logger; + + @Override + protected void starting(Description description) { + super.starting(description); + classLoader = description.getTestClass().getClassLoader(); + logger = Logger.getLogger(description.getTestClass().getName()); + } + + public String getResourceContent(final String resourceName) { + if (resourceName == null) { + throw new IllegalArgumentException("Parameter resourceName cannot be null"); + } + + return getContent(resourceName); + } + + private String getContent(final String resourceName) { + URL resource = classLoader.getResource(resourceName); + InputStream inputStream = null; + Writer writer = new StringWriter(); + String resourceContent = EMPTY; + if (resource != null) { + try { + inputStream = resource.openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + String line = reader.readLine(); + while (line != null) { + writer.write(line); + line = reader.readLine(); + } + resourceContent = writer.toString(); + + } catch (Exception e) { + logger.log(Level.WARNING, "There was an error loading an external resource", e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "There was an error closing input stream", e); + } + try { + writer.close(); + } catch (IOException e) { + logger.log(Level.SEVERE, "There was an error closing writer", e); + } + } + } + return resourceContent; + } +} diff --git a/transferui/src/main/AndroidManifest.xml b/transferui/src/main/AndroidManifest.xml new file mode 100644 index 000000000..8b6760c59 --- /dev/null +++ b/transferui/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferLocalBroadcast.java b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferLocalBroadcast.java new file mode 100644 index 000000000..95b79a982 --- /dev/null +++ b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferLocalBroadcast.java @@ -0,0 +1,21 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Hyperwallet Systems Inc. + * + * 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 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.transfer; + +public class HyperwalletTransferLocalBroadcast { + //todo: add Intents here +} diff --git a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferUi.java b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferUi.java new file mode 100644 index 000000000..0c76f133e --- /dev/null +++ b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferUi.java @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Hyperwallet Systems Inc. + * + * 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 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.transfer; + +import androidx.annotation.NonNull; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; + +/* Class responsible for initializing the Hyperwallet Transfer UI SDK. It contains methods to interact with the + * activities and fragments used to interact with the Hyperwallet platform + */ +public final class HyperwalletTransferUi { + + private static HyperwalletTransferUi sInstance; + + private HyperwalletTransferUi() { + } + + + /** + * @param authenticationTokenProvider An implementation of the {@link HyperwalletAuthenticationTokenProvider} + * @return Returns a newly created HyperwalletTransferUi that can be used to get Intents to launch different + * activities. + */ + public static synchronized HyperwalletTransferUi getInstance( + @NonNull final HyperwalletAuthenticationTokenProvider authenticationTokenProvider) { + if (sInstance == null) { + sInstance = new HyperwalletTransferUi(); + Hyperwallet.getInstance(authenticationTokenProvider); + } + return sInstance; + } + + //todo: Add outer methods here +} From 59fcf27573bb16e07e238b23e611a91fa8bd9820 Mon Sep 17 00:00:00 2001 From: Anna <48258136+azakrevska-epam@users.noreply.github.com> Date: Tue, 30 Jul 2019 01:53:00 +0300 Subject: [PATCH 033/177] Task/single jacoco settings (#78) --- android-library.gradle | 2 +- build.gradle | 3 + commonrepository/build.gradle | 9 +- .../config/jacoco-settings.gradle | 82 ------------------ commonui/build.gradle | 10 ++- commonui/config/jacoco-settings.gradle | 83 ------------------ ...-settings.gradle => jacoco-settings.gradle | 7 +- receiptrepository/build.gradle | 5 +- .../config/jacoco-settings.gradle | 79 ----------------- receiptui/build.gradle | 10 ++- receiptui/config/jacoco-settings.gradle | 82 ------------------ transfermethodrepository/build.gradle | 5 +- .../config/jacoco-settings.gradle | 78 ----------------- transfermethodui/build.gradle | 14 ++- .../config/jacoco-settings.gradle | 86 ------------------- transferrepository/build.gradle | 5 +- .../config/jacoco-settings.gradle | 79 ----------------- transferui/build.gradle | 9 +- transferui/config/jacoco-settings.gradle | 81 ----------------- 19 files changed, 57 insertions(+), 672 deletions(-) delete mode 100644 commonrepository/config/jacoco-settings.gradle delete mode 100644 commonui/config/jacoco-settings.gradle rename userrepository/config/jacoco-settings.gradle => jacoco-settings.gradle (92%) delete mode 100644 receiptrepository/config/jacoco-settings.gradle delete mode 100644 receiptui/config/jacoco-settings.gradle delete mode 100644 transfermethodrepository/config/jacoco-settings.gradle delete mode 100644 transfermethodui/config/jacoco-settings.gradle delete mode 100644 transferrepository/config/jacoco-settings.gradle delete mode 100644 transferui/config/jacoco-settings.gradle diff --git a/android-library.gradle b/android-library.gradle index 750c9a8d9..0a8d7d9e5 100644 --- a/android-library.gradle +++ b/android-library.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'maven-publish' apply plugin: 'signing' apply plugin: 'org.sonarqube' -apply from: "$projectDir/config/jacoco-settings.gradle" +apply from: "../jacoco-settings.gradle" android { compileSdkVersion compileVersion diff --git a/build.gradle b/build.gradle index b411ad0ba..748791345 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,9 @@ subprojects { junitParamsVersion = '1.1.1' robolectricVersion = '4.1' mockWebServerVersion = '3.11.0' + // + jacocoVersion = "0.8.2" + fileFilter = ['**/BuildConfig.*'] } } diff --git a/commonrepository/build.gradle b/commonrepository/build.gradle index 2901b2ef0..2a064cb8a 100644 --- a/commonrepository/build.gradle +++ b/commonrepository/build.gradle @@ -1,7 +1,12 @@ -apply from: "$rootProject.projectDir/android-library.gradle" -description = 'Hyperwallet Common Repository SDK for Android to integrate with the Hyperwallet Platform' project.ext { mavenName = 'Hyperwallet Android Common Repository SDK' + fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/common/repository/EspressoIdlingResource.*', + '**/com/hyperwallet/android/ui/common/repository/Event.*' + ] } +description = 'Hyperwallet Common Repository SDK for Android to integrate with the Hyperwallet Platform' + +apply from: "$rootProject.projectDir/android-library.gradle" apply from: "$rootProject.projectDir/publish.gradle" diff --git a/commonrepository/config/jacoco-settings.gradle b/commonrepository/config/jacoco-settings.gradle deleted file mode 100644 index fd79c8da1..000000000 --- a/commonrepository/config/jacoco-settings.gradle +++ /dev/null @@ -1,82 +0,0 @@ -apply plugin: 'jacoco' - -final def jacocoVersion = "0.8.2" - -jacoco { - toolVersion = jacocoVersion -} - -android { - testOptions { - unitTests { - includeAndroidResources = true - returnDefaultValues = true - } - unitTests.all { - jacoco { - includeNoLocationClasses = true - } - } - } -} - -def fileFilter = ['**/BuildConfig.*', - '**/com/hyperwallet/android/ui/common/repository/EspressoIdlingResource.*', - '**/com/hyperwallet/android/ui/common/repository/Event.*' -] - -def debugClassPaths = [ - '**/intermediates/javac/debug/*/classes/**' -] - -final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] - -task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { - - group = 'Reporting' - description = 'Generate Jacoco coverage reports.' - - reports { - html { - enabled = true - destination file("$buildDir/reports/jacoco") - } - } - - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") -} - -task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { - - group = 'Verification' - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") - - violationRules { - setFailOnViolation(true) - - rule { - element = 'CLASS' - limit { - value = 'COVEREDRATIO' - counter = 'BRANCH' - minimum = 0.65 - } - } - } -} - diff --git a/commonui/build.gradle b/commonui/build.gradle index 30d929e32..5b1152d33 100644 --- a/commonui/build.gradle +++ b/commonui/build.gradle @@ -1,8 +1,14 @@ -apply from: "$rootProject.projectDir/android-library.gradle" -description = 'Hyperwallet Common UI SDK for Android to integrate with the Hyperwallet Platform' project.ext { mavenName = 'Hyperwallet Android Common UI SDK' + fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.*', + '**/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.*', + '**/com/hyperwallet/android/ui/common/view/OneClickListener.*' + ] } +description = 'Hyperwallet Common UI SDK for Android to integrate with the Hyperwallet Platform' + +apply from: "$rootProject.projectDir/android-library.gradle" apply from: "$rootProject.projectDir/publish.gradle" dependencies { diff --git a/commonui/config/jacoco-settings.gradle b/commonui/config/jacoco-settings.gradle deleted file mode 100644 index fa8fde9dd..000000000 --- a/commonui/config/jacoco-settings.gradle +++ /dev/null @@ -1,83 +0,0 @@ -apply plugin: 'jacoco' - -final def jacocoVersion = "0.8.2" - -jacoco { - toolVersion = jacocoVersion -} - -android { - testOptions { - unitTests { - includeAndroidResources = true - returnDefaultValues = true - } - unitTests.all { - jacoco { - includeNoLocationClasses = true - } - } - } -} - -def fileFilter = ['**/BuildConfig.*', - '**/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.*', - '**/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.*', - '**/com/hyperwallet/android/ui/common/view/OneClickListener.*' -] - -def debugClassPaths = [ - '**/intermediates/javac/debug/*/classes/**' -] - -final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] - -task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { - - group = 'Reporting' - description = 'Generate Jacoco coverage reports.' - - reports { - html { - enabled = true - destination file("$buildDir/reports/jacoco") - } - } - - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") -} - -task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { - - group = 'Verification' - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") - - violationRules { - setFailOnViolation(true) - - rule { - element = 'CLASS' - limit { - value = 'COVEREDRATIO' - counter = 'BRANCH' - minimum = 0.65 - } - } - } -} - diff --git a/userrepository/config/jacoco-settings.gradle b/jacoco-settings.gradle similarity index 92% rename from userrepository/config/jacoco-settings.gradle rename to jacoco-settings.gradle index 66eb192b2..d75c8a472 100644 --- a/userrepository/config/jacoco-settings.gradle +++ b/jacoco-settings.gradle @@ -1,9 +1,7 @@ apply plugin: 'jacoco' -final def jacocoVersion = "0.8.2" - jacoco { - toolVersion = jacocoVersion + toolVersion = project.ext.jacocoVersion } android { @@ -20,7 +18,6 @@ android { } } -def fileFilter = ['**/BuildConfig.*'] def debugClassPaths = [ '**/intermediates/javac/debug/*/classes/**' ] @@ -42,7 +39,7 @@ task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { classDirectories = fileTree( dir: "${buildDir}", includes: debugClassPaths, - excludes: fileFilter + excludes: project.ext.fileFilter ) additionalSourceDirs = files(coverageSourceDirs) diff --git a/receiptrepository/build.gradle b/receiptrepository/build.gradle index f5390c2fe..f3a8964cd 100644 --- a/receiptrepository/build.gradle +++ b/receiptrepository/build.gradle @@ -1,8 +1,9 @@ -apply from: "$rootProject.projectDir/android-library.gradle" -description = 'Hyperwallet Receipt Repository SDK for Android to integrate with the Hyperwallet Platform' project.ext { mavenName = 'Hyperwallet Android Receipt Repository SDK' } +description = 'Hyperwallet Receipt Repository SDK for Android to integrate with the Hyperwallet Platform' + +apply from: "$rootProject.projectDir/android-library.gradle" apply from: "$rootProject.projectDir/publish.gradle" diff --git a/receiptrepository/config/jacoco-settings.gradle b/receiptrepository/config/jacoco-settings.gradle deleted file mode 100644 index bb4ffa228..000000000 --- a/receiptrepository/config/jacoco-settings.gradle +++ /dev/null @@ -1,79 +0,0 @@ -apply plugin: 'jacoco' - -final def jacocoVersion = "0.8.2" - -jacoco { - toolVersion = jacocoVersion -} - -android { - testOptions { - unitTests { - includeAndroidResources = true - returnDefaultValues = true - } - unitTests.all { - jacoco { - includeNoLocationClasses = true - } - } - } -} - -def fileFilter = ['**/BuildConfig.*' -] - -def debugClassPaths = [ - '**/intermediates/javac/debug/*/classes/**' -] - -final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] - -task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { - - group = 'Reporting' - description = 'Generate Jacoco coverage reports.' - reports { - html { - enabled = true - destination file("$project.buildDir/reports/jacoco") - } - } - - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") -} - -task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { - - group = 'Verification' - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") - - violationRules { - setFailOnViolation(true) - - rule { - element = 'CLASS' - limit { - value = 'COVEREDRATIO' - counter = 'BRANCH' - minimum = 0.65 - } - } - } -} - diff --git a/receiptui/build.gradle b/receiptui/build.gradle index d24766afc..6af23af41 100644 --- a/receiptui/build.gradle +++ b/receiptui/build.gradle @@ -1,8 +1,14 @@ -apply from: "$rootProject.projectDir/android-library.gradle" -description = 'Hyperwallet Receipt UI SDK for Android to integrate with the Hyperwallet Platform' project.ext { mavenName = 'Hyperwallet Android Receipt UI SDK' + fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/receipt/HyperwalletReceiptUi.*', + '**/com/hyperwallet/android/ui/receipt/view/*.*', + '**/com/hyperwallet/android/ui/receipt/viewmodel/*.*' + ] } +description = 'Hyperwallet Receipt UI SDK for Android to integrate with the Hyperwallet Platform' + +apply from: "$rootProject.projectDir/android-library.gradle" apply from: "$rootProject.projectDir/publish.gradle" dependencies { diff --git a/receiptui/config/jacoco-settings.gradle b/receiptui/config/jacoco-settings.gradle deleted file mode 100644 index c293d9a13..000000000 --- a/receiptui/config/jacoco-settings.gradle +++ /dev/null @@ -1,82 +0,0 @@ -apply plugin: 'jacoco' - -final def jacocoVersion = "0.8.2" - -jacoco { - toolVersion = jacocoVersion -} - -android { - testOptions { - unitTests { - includeAndroidResources = true - returnDefaultValues = true - } - unitTests.all { - jacoco { - includeNoLocationClasses = true - } - } - } -} - -def fileFilter = ['**/BuildConfig.*', - '**/com/hyperwallet/android/ui/receipt/HyperwalletReceiptUi.*', - '**/com/hyperwallet/android/ui/receipt/view/*.*', - '**/com/hyperwallet/android/ui/receipt/viewmodel/*.*' -] - -def debugClassPaths = [ - '**/intermediates/javac/debug/*/classes/**' -] - -final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] - -task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { - - group = 'Reporting' - description = 'Generate Jacoco coverage reports.' - reports { - html { - enabled = true - destination file("$project.buildDir/reports/jacoco") - } - } - - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") -} - -task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { - - group = 'Verification' - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") - - violationRules { - setFailOnViolation(true) - - rule { - element = 'CLASS' - limit { - value = 'COVEREDRATIO' - counter = 'BRANCH' - minimum = 0.65 - } - } - } -} - diff --git a/transfermethodrepository/build.gradle b/transfermethodrepository/build.gradle index 5f8b12e95..26d68c35d 100644 --- a/transfermethodrepository/build.gradle +++ b/transfermethodrepository/build.gradle @@ -1,8 +1,9 @@ -apply from: "$rootProject.projectDir/android-library.gradle" -description = 'Hyperwallet Transfer Method Repository SDK for Android to integrate with the Hyperwallet Platform' project.ext { mavenName = 'Hyperwallet Android Transfer Method Repository SDK' } +description = 'Hyperwallet Transfer Method Repository SDK for Android to integrate with the Hyperwallet Platform' + +apply from: "$rootProject.projectDir/android-library.gradle" apply from: "$rootProject.projectDir/publish.gradle" dependencies { diff --git a/transfermethodrepository/config/jacoco-settings.gradle b/transfermethodrepository/config/jacoco-settings.gradle deleted file mode 100644 index f1b0a7c45..000000000 --- a/transfermethodrepository/config/jacoco-settings.gradle +++ /dev/null @@ -1,78 +0,0 @@ -apply plugin: 'jacoco' - -final def jacocoVersion = "0.8.2" - -jacoco { - toolVersion = jacocoVersion -} - -android { - testOptions { - unitTests { - includeAndroidResources = true - returnDefaultValues = true - } - unitTests.all { - jacoco { - includeNoLocationClasses = true - } - } - } -} - -def fileFilter = ['**/BuildConfig.*'] - -def debugClassPaths = [ - '**/intermediates/javac/debug/*/classes/**' -] - -final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] - -task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { - - group = 'Reporting' - description = 'Generate Jacoco coverage reports.' - reports { - html { - enabled = true - destination file("$project.buildDir/reports/jacoco") - } - } - - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") -} - -task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { - - group = 'Verification' - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") - - violationRules { - setFailOnViolation(true) - - rule { - element = 'CLASS' - limit { - value = 'COVEREDRATIO' - counter = 'BRANCH' - minimum = 0.65 - } - } - } -} - diff --git a/transfermethodui/build.gradle b/transfermethodui/build.gradle index fe72e3da1..22785ac99 100644 --- a/transfermethodui/build.gradle +++ b/transfermethodui/build.gradle @@ -1,8 +1,18 @@ -apply from: "$rootProject.projectDir/android-library.gradle" -description = 'Hyperwallet Transfer Method UI SDK for Android to integrate with the Hyperwallet Platform' project.ext { mavenName = 'Hyperwallet Android Transfer Method UI SDK' + fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodUi.*', + '**/com/hyperwallet/android/ui/transfermethod/**/*Activity*.*', + '**/com/hyperwallet/android/ui/transfermethod/**/*Fragment*.*', + '**/com/hyperwallet/android/ui/transfermethod/view/TransferMethodSelectionItem.*', + '**/com/hyperwallet/android/ui/transfermethod/view/TransferMethodUtils.*', + '**/com/hyperwallet/android/ui/transfermethod/view/HorizontalDividerItemDecorator.*', + '**/com/hyperwallet/android/ui/transfermethod/view/widget/*' + ] } +description = 'Hyperwallet Transfer Method UI SDK for Android to integrate with the Hyperwallet Platform' + +apply from: "$rootProject.projectDir/android-library.gradle" apply from: "$rootProject.projectDir/publish.gradle" dependencies { diff --git a/transfermethodui/config/jacoco-settings.gradle b/transfermethodui/config/jacoco-settings.gradle deleted file mode 100644 index 725c470eb..000000000 --- a/transfermethodui/config/jacoco-settings.gradle +++ /dev/null @@ -1,86 +0,0 @@ -apply plugin: 'jacoco' - -final def jacocoVersion = "0.8.2" - -jacoco { - toolVersion = jacocoVersion -} - -android { - testOptions { - unitTests { - includeAndroidResources = true - returnDefaultValues = true - } - unitTests.all { - jacoco { - includeNoLocationClasses = true - } - } - } -} - -def fileFilter = ['**/BuildConfig.*', - '**/com/hyperwallet/android/ui/transfermethod/HyperwalletTransferMethodUi.*', - '**/com/hyperwallet/android/ui/transfermethod/**/*Activity*.*', - '**/com/hyperwallet/android/ui/transfermethod/**/*Fragment*.*', - '**/com/hyperwallet/android/ui/transfermethod/view/TransferMethodSelectionItem.*', - '**/com/hyperwallet/android/ui/transfermethod/view/TransferMethodUtils.*', - '**/com/hyperwallet/android/ui/transfermethod/view/HorizontalDividerItemDecorator.*', - '**/com/hyperwallet/android/ui/transfermethod/view/widget/*' -] -def debugClassPaths = [ - '**/intermediates/javac/debug/*/classes/**' -] - -final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] - -task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { - - group = 'Reporting' - description = 'Generate Jacoco coverage reports.' - - reports { - html { - enabled = true - destination file("$buildDir/reports/jacoco") - } - } - - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") -} - -task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { - - group = 'Verification' - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") - - violationRules { - setFailOnViolation(true) - - rule { - element = 'CLASS' - limit { - value = 'COVEREDRATIO' - counter = 'BRANCH' - minimum = 0.65 - } - } - } -} - diff --git a/transferrepository/build.gradle b/transferrepository/build.gradle index 12fc432a2..dcd8fba0f 100644 --- a/transferrepository/build.gradle +++ b/transferrepository/build.gradle @@ -1,8 +1,9 @@ -apply from: "$rootProject.projectDir/android-library.gradle" -description = 'Hyperwallet Transfer Repository SDK for Android to integrate with the Hyperwallet Platform' project.ext { mavenName = 'Hyperwallet Android Transfer Repository SDK' } +description = 'Hyperwallet Transfer Repository SDK for Android to integrate with the Hyperwallet Platform' + +apply from: "$rootProject.projectDir/android-library.gradle" apply from: "$rootProject.projectDir/publish.gradle" dependencies { diff --git a/transferrepository/config/jacoco-settings.gradle b/transferrepository/config/jacoco-settings.gradle deleted file mode 100644 index bb4ffa228..000000000 --- a/transferrepository/config/jacoco-settings.gradle +++ /dev/null @@ -1,79 +0,0 @@ -apply plugin: 'jacoco' - -final def jacocoVersion = "0.8.2" - -jacoco { - toolVersion = jacocoVersion -} - -android { - testOptions { - unitTests { - includeAndroidResources = true - returnDefaultValues = true - } - unitTests.all { - jacoco { - includeNoLocationClasses = true - } - } - } -} - -def fileFilter = ['**/BuildConfig.*' -] - -def debugClassPaths = [ - '**/intermediates/javac/debug/*/classes/**' -] - -final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] - -task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { - - group = 'Reporting' - description = 'Generate Jacoco coverage reports.' - reports { - html { - enabled = true - destination file("$project.buildDir/reports/jacoco") - } - } - - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") -} - -task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { - - group = 'Verification' - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") - - violationRules { - setFailOnViolation(true) - - rule { - element = 'CLASS' - limit { - value = 'COVEREDRATIO' - counter = 'BRANCH' - minimum = 0.65 - } - } - } -} - diff --git a/transferui/build.gradle b/transferui/build.gradle index 4b5738db4..c7f37807e 100644 --- a/transferui/build.gradle +++ b/transferui/build.gradle @@ -1,8 +1,13 @@ -apply from: "$rootProject.projectDir/android-library.gradle" -description = 'Hyperwallet Transfer UI SDK for Android to integrate with the Hyperwallet Platform' project.ext { mavenName = 'Hyperwallet Android Transfer UI SDK' + fileFilter = ['**/BuildConfig.*', + '**/com/hyperwallet/android/ui/transfer/view/*.*', + '**/com/hyperwallet/android/ui/transfer/viewmodel/*.*' + ] } +description = 'Hyperwallet Transfer UI SDK for Android to integrate with the Hyperwallet Platform' + +apply from: "$rootProject.projectDir/android-library.gradle" apply from: "$rootProject.projectDir/publish.gradle" dependencies { diff --git a/transferui/config/jacoco-settings.gradle b/transferui/config/jacoco-settings.gradle deleted file mode 100644 index f8110818c..000000000 --- a/transferui/config/jacoco-settings.gradle +++ /dev/null @@ -1,81 +0,0 @@ -apply plugin: 'jacoco' - -final def jacocoVersion = "0.8.2" - -jacoco { - toolVersion = jacocoVersion -} - -android { - testOptions { - unitTests { - includeAndroidResources = true - returnDefaultValues = true - } - unitTests.all { - jacoco { - includeNoLocationClasses = true - } - } - } -} - -def fileFilter = ['**/BuildConfig.*', - '**/com/hyperwallet/android/ui/transfer/view/*.*', - '**/com/hyperwallet/android/ui/transfer/viewmodel/*.*' -] - -def debugClassPaths = [ - '**/intermediates/javac/debug/*/classes/**' -] - -final def coverageSourceDirs = ["$project.projectDir/src/main/java/*"] - -task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { - - group = 'Reporting' - description = 'Generate Jacoco coverage reports.' - reports { - html { - enabled = true - destination file("$project.buildDir/reports/jacoco") - } - } - - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") -} - -task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn: 'jacocoTestReport') { - - group = 'Verification' - classDirectories = fileTree( - dir: "${buildDir}", - includes: debugClassPaths, - excludes: fileFilter - ) - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec") - - violationRules { - setFailOnViolation(true) - - rule { - element = 'CLASS' - limit { - value = 'COVEREDRATIO' - counter = 'BRANCH' - minimum = 0.65 - } - } - } -} - From 0155f92b57122b9e43323e2b93ac3bcedb287ce3 Mon Sep 17 00:00:00 2001 From: Shyang Koong Date: Wed, 31 Jul 2019 15:03:21 -0700 Subject: [PATCH 034/177] Moving test util and rules into separate module (#80) --- receiptrepository/build.gradle | 1 + .../PrepaidCardReceiptDataSourceTest.java | 2 +- .../repository/UserReceiptDataSourceTest.java | 2 +- .../HyperwalletExternalResourceManager.java | 72 ------- receiptui/build.gradle | 3 + .../receipt/ListPrepaidCardReceiptsTest.java | 10 +- .../ui/receipt/ListUserReceiptsTest.java | 10 +- .../HyperwalletExternalResourceManager.java | 72 ------- .../viewmodel/ReceiptDetailViewModelTest.java | 2 +- settings.gradle | 3 +- testutils/.gitignore | 1 + testutils/build.gradle | 9 + testutils/config/lint.xml | 7 + testutils/proguard-rules.pro | 21 ++ testutils/src/main/AndroidManifest.xml | 2 + .../TestAuthenticationProvider.java | 2 +- .../HyperwalletExternalResourceManager.java | 2 +- .../rule/HyperwalletMockWebServer.java | 2 +- .../ui/testutils}/util/EspressoUtils.java | 2 +- .../testutils}/util/NestedScrollToAction.java | 18 +- .../util/RecyclerViewCountAssertion.java | 10 +- testutils/src/main/res/values/strings.xml | 3 + transfermethodrepository/build.gradle | 2 + ...MethodConfigurationRepositoryImplTest.java | 2 +- .../HyperwalletExternalResourceManager.java | 74 ------- transfermethodui/build.gradle | 2 + .../transfermethod/AddTransferMethodTest.java | 8 +- .../ui/transfermethod/BankAccountTest.java | 18 +- .../ui/transfermethod/BankCardTest.java | 14 +- .../ListTransferMethodTest.java | 12 +- .../android/ui/transfermethod/PayPalTest.java | 14 +- .../SelectTransferMethodTest.java | 12 +- .../HyperwalletExternalResourceManager.java | 73 ------- .../rule/HyperwalletMockWebServer.java | 115 ----------- .../ui/transfermethod/util/EspressoUtils.java | 187 ------------------ .../util/NestedScrollToAction.java | 41 ---- .../util/RecyclerViewCountAssertion.java | 30 --- .../util/TestAuthenticationProvider.java | 51 ----- .../AddTransferMethodPresenterTest.java | 2 +- .../ui/transfermethod/FeeFormatterTest.java | 2 +- .../SelectTransferMethodPresenterTest.java | 2 +- .../TransferMethodUtilsTest.java | 2 +- .../HyperwalletExternalResourceManager.java | 74 ------- .../HyperwalletExternalResourceManager.java | 72 ------- .../HyperwalletExternalResourceManager.java | 73 ------- 45 files changed, 125 insertions(+), 1013 deletions(-) delete mode 100644 receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java delete mode 100644 receiptui/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java create mode 100644 testutils/.gitignore create mode 100644 testutils/build.gradle create mode 100644 testutils/config/lint.xml create mode 100644 testutils/proguard-rules.pro create mode 100644 testutils/src/main/AndroidManifest.xml rename {receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util => testutils/src/main/java/com/hyperwallet/android/ui/testutils}/TestAuthenticationProvider.java (97%) rename {receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt => testutils/src/main/java/com/hyperwallet/android/ui/testutils}/rule/HyperwalletExternalResourceManager.java (97%) rename {receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt => testutils/src/main/java/com/hyperwallet/android/ui/testutils}/rule/HyperwalletMockWebServer.java (98%) rename {receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt => testutils/src/main/java/com/hyperwallet/android/ui/testutils}/util/EspressoUtils.java (99%) rename {receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt => testutils/src/main/java/com/hyperwallet/android/ui/testutils}/util/NestedScrollToAction.java (56%) rename {receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt => testutils/src/main/java/com/hyperwallet/android/ui/testutils}/util/RecyclerViewCountAssertion.java (77%) create mode 100644 testutils/src/main/res/values/strings.xml delete mode 100644 transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java delete mode 100644 transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java delete mode 100644 transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletMockWebServer.java delete mode 100644 transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/EspressoUtils.java delete mode 100644 transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/NestedScrollToAction.java delete mode 100644 transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/RecyclerViewCountAssertion.java delete mode 100644 transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/TestAuthenticationProvider.java delete mode 100644 transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java delete mode 100644 transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java delete mode 100644 transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java diff --git a/receiptrepository/build.gradle b/receiptrepository/build.gradle index f3a8964cd..2c7f54326 100644 --- a/receiptrepository/build.gradle +++ b/receiptrepository/build.gradle @@ -14,4 +14,5 @@ dependencies { api project(':commonrepository') testImplementation "org.robolectric:robolectric:$robolectricVersion" + testImplementation project(':testutils') } \ No newline at end of file diff --git a/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java index fd468bfab..b308261a7 100644 --- a/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java +++ b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/PrepaidCardReceiptDataSourceTest.java @@ -29,7 +29,7 @@ import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.model.receipt.ReceiptQueryParam; -import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.util.DateUtil; import org.hamcrest.Matchers; diff --git a/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java index a26ed1b15..47652e6fa 100644 --- a/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java +++ b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/repository/UserReceiptDataSourceTest.java @@ -27,7 +27,7 @@ import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; import com.hyperwallet.android.model.receipt.ReceiptQueryParam; -import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; import org.hamcrest.Matchers; import org.json.JSONObject; diff --git a/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java b/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java deleted file mode 100644 index abc9bf5da..000000000 --- a/receiptrepository/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.hyperwallet.android.ui.receipt.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class HyperwalletExternalResourceManager extends TestWatcher { - - private static final String EMPTY = ""; - private ClassLoader classLoader; - private Logger logger; - - @Override - protected void starting(Description description) { - super.starting(description); - classLoader = description.getTestClass().getClassLoader(); - logger = Logger.getLogger(description.getTestClass().getName()); - } - - public String getResourceContent(final String resourceName) { - if (resourceName == null) { - throw new IllegalArgumentException("Parameter resourceName cannot be null"); - } - - return getContent(resourceName); - } - - private String getContent(final String resourceName) { - URL resource = classLoader.getResource(resourceName); - InputStream inputStream = null; - Writer writer = new StringWriter(); - String resourceContent = EMPTY; - if (resource != null) { - try { - inputStream = resource.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); - String line = reader.readLine(); - while (line != null) { - writer.write(line); - line = reader.readLine(); - } - resourceContent = writer.toString(); - - } catch (Exception e) { - logger.log(Level.WARNING, "There was an error loading an external resource", e); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "There was an error closing input stream", e); - } - try { - writer.close(); - } catch (IOException e) { - logger.log(Level.SEVERE, "There was an error closing writer", e); - } - } - } - return resourceContent; - } -} diff --git a/receiptui/build.gradle b/receiptui/build.gradle index 6af23af41..f05299166 100644 --- a/receiptui/build.gradle +++ b/receiptui/build.gradle @@ -23,10 +23,13 @@ dependencies { implementation "androidx.paging:paging-runtime:$pagingRuntimeVersion" testImplementation "org.robolectric:robolectric:$robolectricVersion" + testImplementation project(':testutils') + androidTestImplementation "androidx.test:rules:$testRulesVersion" androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockServerVersion" androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanaryVersion" androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:$leakcanaryVersion" + androidTestImplementation project(':testutils') } diff --git a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java index 910d69628..f6691fb0f 100644 --- a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java +++ b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListPrepaidCardReceiptsTest.java @@ -24,8 +24,8 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT; import static java.net.HttpURLConnection.HTTP_OK; -import static com.hyperwallet.android.ui.receipt.util.EspressoUtils.atPosition; import static com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity.EXTRA_PREPAID_CARD_TOKEN; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.atPosition; import android.content.Context; import android.content.Intent; @@ -43,11 +43,11 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; import com.hyperwallet.android.ui.common.util.DateUtils; -import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.receipt.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.receipt.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.ui.receipt.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.receipt.view.ListPrepaidCardReceiptActivity; +import com.hyperwallet.android.ui.testutils.TestAuthenticationProvider; +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 org.junit.After; import org.junit.Before; diff --git a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java index 37809b494..b3b89ad17 100644 --- a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java +++ b/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/ListUserReceiptsTest.java @@ -24,7 +24,7 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT; import static java.net.HttpURLConnection.HTTP_OK; -import static com.hyperwallet.android.ui.receipt.util.EspressoUtils.atPosition; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.atPosition; import android.content.Context; import android.content.res.Configuration; @@ -41,11 +41,11 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; import com.hyperwallet.android.ui.common.util.DateUtils; -import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.receipt.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.receipt.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.ui.receipt.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.receipt.view.ListUserReceiptActivity; +import com.hyperwallet.android.ui.testutils.TestAuthenticationProvider; +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 org.junit.After; import org.junit.Before; diff --git a/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java deleted file mode 100644 index abc9bf5da..000000000 --- a/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.hyperwallet.android.ui.receipt.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class HyperwalletExternalResourceManager extends TestWatcher { - - private static final String EMPTY = ""; - private ClassLoader classLoader; - private Logger logger; - - @Override - protected void starting(Description description) { - super.starting(description); - classLoader = description.getTestClass().getClassLoader(); - logger = Logger.getLogger(description.getTestClass().getName()); - } - - public String getResourceContent(final String resourceName) { - if (resourceName == null) { - throw new IllegalArgumentException("Parameter resourceName cannot be null"); - } - - return getContent(resourceName); - } - - private String getContent(final String resourceName) { - URL resource = classLoader.getResource(resourceName); - InputStream inputStream = null; - Writer writer = new StringWriter(); - String resourceContent = EMPTY; - if (resource != null) { - try { - inputStream = resource.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); - String line = reader.readLine(); - while (line != null) { - writer.write(line); - line = reader.readLine(); - } - resourceContent = writer.toString(); - - } catch (Exception e) { - logger.log(Level.WARNING, "There was an error loading an external resource", e); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "There was an error closing input stream", e); - } - try { - writer.close(); - } catch (IOException e) { - logger.log(Level.SEVERE, "There was an error closing writer", e); - } - } - } - return resourceContent; - } -} diff --git a/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModelTest.java b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModelTest.java index 0f965e28c..b0f3e9166 100644 --- a/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModelTest.java +++ b/receiptui/src/test/java/com/hyperwallet/android/ui/receipt/viewmodel/ReceiptDetailViewModelTest.java @@ -14,8 +14,8 @@ import com.hyperwallet.android.exception.HyperwalletException; import com.hyperwallet.android.model.paging.HyperwalletPageList; import com.hyperwallet.android.model.receipt.Receipt; -import com.hyperwallet.android.ui.receipt.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.receipt.view.ReceiptDetailActivity; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; import org.json.JSONException; import org.json.JSONObject; diff --git a/settings.gradle b/settings.gradle index 2dc592721..5936c0594 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,4 +6,5 @@ include ':commonui', ':transfermethodui', ':transferrepository', ':transferui', - ':userrepository' + ':userrepository', + ':testutils' diff --git a/testutils/.gitignore b/testutils/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/testutils/.gitignore @@ -0,0 +1 @@ +/build diff --git a/testutils/build.gradle b/testutils/build.gradle new file mode 100644 index 000000000..b174bee8e --- /dev/null +++ b/testutils/build.gradle @@ -0,0 +1,9 @@ +description = 'Test Utils for Hyperwallet UI SDK' + +apply from: "$rootProject.projectDir/android-library.gradle" + +dependencies { + implementation "androidx.test:rules:$testRulesVersion" + implementation "androidx.test.espresso:espresso-core:$espressoVersion" + implementation "com.squareup.okhttp3:mockwebserver:$mockServerVersion" +} diff --git a/testutils/config/lint.xml b/testutils/config/lint.xml new file mode 100644 index 000000000..3c83d4bb5 --- /dev/null +++ b/testutils/config/lint.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/testutils/proguard-rules.pro b/testutils/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/testutils/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/testutils/src/main/AndroidManifest.xml b/testutils/src/main/AndroidManifest.xml new file mode 100644 index 000000000..176cdbe88 --- /dev/null +++ b/testutils/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/TestAuthenticationProvider.java similarity index 97% rename from receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java rename to testutils/src/main/java/com/hyperwallet/android/ui/testutils/TestAuthenticationProvider.java index c50513b47..e59520ec8 100644 --- a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/TestAuthenticationProvider.java +++ b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/TestAuthenticationProvider.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.receipt.util; +package com.hyperwallet.android.ui.testutils; import com.hyperwallet.android.HyperwalletAuthenticationTokenListener; import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; diff --git a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/rule/HyperwalletExternalResourceManager.java similarity index 97% rename from receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java rename to testutils/src/main/java/com/hyperwallet/android/ui/testutils/rule/HyperwalletExternalResourceManager.java index b5baa31da..c61e9039b 100644 --- a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletExternalResourceManager.java +++ b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/rule/HyperwalletExternalResourceManager.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.receipt.rule; +package com.hyperwallet.android.ui.testutils.rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; diff --git a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/rule/HyperwalletMockWebServer.java similarity index 98% rename from receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java rename to testutils/src/main/java/com/hyperwallet/android/ui/testutils/rule/HyperwalletMockWebServer.java index fd55bd2bb..a50ad0adf 100644 --- a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/rule/HyperwalletMockWebServer.java +++ b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/rule/HyperwalletMockWebServer.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.receipt.rule; +package com.hyperwallet.android.ui.testutils.rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; diff --git a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/util/EspressoUtils.java similarity index 99% rename from receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java rename to testutils/src/main/java/com/hyperwallet/android/ui/testutils/util/EspressoUtils.java index 549a99704..2f34b9fce 100644 --- a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/EspressoUtils.java +++ b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/util/EspressoUtils.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.receipt.util; +package com.hyperwallet.android.ui.testutils.util; import android.graphics.Bitmap; import android.graphics.Canvas; diff --git a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/util/NestedScrollToAction.java similarity index 56% rename from receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java rename to testutils/src/main/java/com/hyperwallet/android/ui/testutils/util/NestedScrollToAction.java index b3619e5c3..af346ccb6 100644 --- a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/NestedScrollToAction.java +++ b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/util/NestedScrollToAction.java @@ -1,11 +1,4 @@ -package com.hyperwallet.android.ui.receipt.util; - -import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; -import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; -import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; - -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anyOf; +package com.hyperwallet.android.ui.testutils.util; import android.view.View; @@ -16,6 +9,7 @@ import androidx.test.espresso.matcher.ViewMatchers; import org.hamcrest.Matcher; +import org.hamcrest.Matchers; public class NestedScrollToAction implements ViewAction { private static final String TAG = ScrollToAction.class.getSimpleName(); @@ -23,10 +17,10 @@ public class NestedScrollToAction implements ViewAction { @SuppressWarnings("unchecked") @Override public Matcher getConstraints() { - return allOf( - withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), - isDescendantOfA( - anyOf(isAssignableFrom(NestedScrollView.class)))); + return Matchers.allOf( + ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), + ViewMatchers.isDescendantOfA( + Matchers.anyOf(ViewMatchers.isAssignableFrom(NestedScrollView.class)))); } @Override diff --git a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/util/RecyclerViewCountAssertion.java similarity index 77% rename from receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java rename to testutils/src/main/java/com/hyperwallet/android/ui/testutils/util/RecyclerViewCountAssertion.java index 7420f7e5c..a86049961 100644 --- a/receiptui/src/androidTest/java/com/hyperwallet/android/ui/receipt/util/RecyclerViewCountAssertion.java +++ b/testutils/src/main/java/com/hyperwallet/android/ui/testutils/util/RecyclerViewCountAssertion.java @@ -1,7 +1,4 @@ -package com.hyperwallet.android.ui.receipt.util; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; +package com.hyperwallet.android.ui.testutils.util; import android.view.View; @@ -9,6 +6,9 @@ import androidx.test.espresso.NoMatchingViewException; import androidx.test.espresso.ViewAssertion; +import org.hamcrest.CoreMatchers; +import org.hamcrest.MatcherAssert; + public class RecyclerViewCountAssertion implements ViewAssertion { private final int mCount; @@ -25,6 +25,6 @@ public void check(View view, NoMatchingViewException noViewFoundException) { RecyclerView recyclerView = (RecyclerView) view; RecyclerView.Adapter adapter = recyclerView.getAdapter(); - assertThat(adapter.getItemCount(), is(mCount)); + MatcherAssert.assertThat(adapter.getItemCount(), CoreMatchers.is(mCount)); } } diff --git a/testutils/src/main/res/values/strings.xml b/testutils/src/main/res/values/strings.xml new file mode 100644 index 000000000..215cb49b4 --- /dev/null +++ b/testutils/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Test Utils + diff --git a/transfermethodrepository/build.gradle b/transfermethodrepository/build.gradle index 26d68c35d..4b6a11851 100644 --- a/transfermethodrepository/build.gradle +++ b/transfermethodrepository/build.gradle @@ -8,6 +8,8 @@ apply from: "$rootProject.projectDir/publish.gradle" dependencies { api project(':commonrepository') + testImplementation "org.robolectric:robolectric:$robolectricVersion" testImplementation "com.squareup.okhttp3:mockwebserver:$mockWebServerVersion" + testImplementation project(':testutils') } \ No newline at end of file diff --git a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImplTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImplTest.java index b71175ead..36c4926a6 100644 --- a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImplTest.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodConfigurationRepositoryImplTest.java @@ -32,7 +32,7 @@ import com.hyperwallet.android.model.graphql.keyed.HyperwalletTransferMethodConfigurationKeyResult; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationFieldQuery; import com.hyperwallet.android.model.graphql.query.HyperwalletTransferMethodConfigurationKeysQuery; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.util.JsonUtils; import org.hamcrest.collection.IsEmptyCollection; diff --git a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java deleted file mode 100644 index 4db98b20a..000000000 --- a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.hyperwallet.android.ui.transfermethod.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class HyperwalletExternalResourceManager extends TestWatcher { - - private static final String EMPTY = ""; - private ClassLoader classLoader; - private Logger logger; - - @Override - protected void starting(Description description) { - super.starting(description); - classLoader = description.getTestClass().getClassLoader(); - logger = Logger.getLogger(description.getTestClass().getName()); - } - - - public String getResourceContent(final String resourceName) { - if (resourceName == null) { - throw new IllegalArgumentException("Parameter resourceName cannot be null"); - } - - return getContent(resourceName); - } - - private String getContent(final String resourceName) { - - URL resource = classLoader.getResource(resourceName); - InputStream inputStream = null; - Writer writer = new StringWriter(); - String resourceContent = EMPTY; - if (resource != null) { - try { - inputStream = resource.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); - String line = reader.readLine(); - while (line != null) { - writer.write(line); - line = reader.readLine(); - } - resourceContent = writer.toString(); - - } catch (Exception e) { - logger.log(Level.WARNING, "There was an error loading an external resource", e); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "There was an error closing input stream", e); - } - try { - writer.close(); - } catch (IOException e) { - logger.log(Level.SEVERE, "There was an error closing writer", e); - } - } - } - return resourceContent; - } -} diff --git a/transfermethodui/build.gradle b/transfermethodui/build.gradle index 22785ac99..d4c6f6427 100644 --- a/transfermethodui/build.gradle +++ b/transfermethodui/build.gradle @@ -33,7 +33,9 @@ dependencies { androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockServerVersion" androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanaryVersion" androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:$leakcanaryVersion" + androidTestImplementation project(":testutils") testImplementation "org.robolectric:robolectric:$robolectricVersion" testImplementation "com.squareup.okhttp3:mockwebserver:$mockWebServerVersion" + testImplementation project(':testutils') } \ No newline at end of file diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java index 243350ad1..89ebb4bb0 100644 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodTest.java @@ -22,7 +22,7 @@ import static java.net.HttpURLConnection.HTTP_OK; import static com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment.RESULT_ERROR; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.nestedScrollTo; import android.app.Instrumentation; import android.content.Intent; @@ -38,10 +38,10 @@ 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.TestAuthenticationProvider; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity; import org.junit.After; diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java index 414521218..77e40b46e 100644 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankAccountTest.java @@ -24,11 +24,11 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount.Purpose.SAVINGS; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasEmptyText; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasErrorText; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasNoErrorText; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.nestedScrollTo; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withHint; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.hasEmptyText; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.hasNoErrorText; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.withHint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -48,11 +48,11 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.testutils.TestAuthenticationProvider; +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.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.transfermethod.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity; import org.junit.After; diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java index 508c397f8..0ae593cd4 100644 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/BankCardTest.java @@ -22,10 +22,10 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.concurrent.TimeUnit.SECONDS; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasEmptyText; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasErrorText; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.nestedScrollTo; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withHint; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.hasEmptyText; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.withHint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -45,10 +45,10 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.testutils.TestAuthenticationProvider; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity; import org.junit.After; diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java index b45308b86..2bf7349a8 100644 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/ListTransferMethodTest.java @@ -21,8 +21,8 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static com.hyperwallet.android.model.StatusTransition.StatusDefinition.DE_ACTIVATED; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.atPosition; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withDrawable; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.atPosition; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.withDrawable; import android.content.BroadcastReceiver; import android.content.Context; @@ -40,11 +40,11 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.model.StatusTransition; import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.testutils.TestAuthenticationProvider; +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.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.transfermethod.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.transfermethod.view.ListTransferMethodActivity; import org.hamcrest.Matchers; diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java index f61bec357..5fdf9f0c5 100644 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/PayPalTest.java @@ -24,10 +24,10 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.concurrent.TimeUnit.SECONDS; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasEmptyText; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.hasErrorText; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.nestedScrollTo; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withHint; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.hasEmptyText; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.hasErrorText; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.nestedScrollTo; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.withHint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -47,10 +47,10 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.testutils.TestAuthenticationProvider; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletMockWebServer; import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity; import org.junit.After; diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java index 68acebad9..c8d750124 100644 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java +++ b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodTest.java @@ -25,8 +25,8 @@ import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; import static com.hyperwallet.android.model.user.HyperwalletUser.ProfileTypes.BUSINESS; import static com.hyperwallet.android.model.user.HyperwalletUser.ProfileTypes.INDIVIDUAL; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.atPosition; -import static com.hyperwallet.android.ui.transfermethod.util.EspressoUtils.withDrawable; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.atPosition; +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.withDrawable; import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_COUNTRY; import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_CURRENCY; import static com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodActivity.EXTRA_TRANSFER_METHOD_PROFILE_TYPE; @@ -44,11 +44,11 @@ import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.ui.R; import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.testutils.TestAuthenticationProvider; +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.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletMockWebServer; -import com.hyperwallet.android.ui.transfermethod.util.RecyclerViewCountAssertion; -import com.hyperwallet.android.ui.transfermethod.util.TestAuthenticationProvider; import com.hyperwallet.android.ui.transfermethod.view.SelectTransferMethodActivity; import com.hyperwallet.android.ui.user.repository.UserRepositoryFactory; diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java deleted file mode 100644 index 68e288a5b..000000000 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.hyperwallet.android.ui.transfermethod.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class HyperwalletExternalResourceManager extends TestWatcher { - - private static final String EMPTY = ""; - private ClassLoader classLoader; - private Logger logger; - - @Override - protected void starting(Description description) { - super.starting(description); - classLoader = description.getTestClass().getClassLoader(); - logger = Logger.getLogger(description.getTestClass().getName()); - } - - public String getResourceContent(final String resourceName) { - if (resourceName == null) { - throw new IllegalArgumentException("Parameter resourceName cannot be null"); - } - - return getContent(resourceName); - } - - private String getContent(final String resourceName) { - - URL resource = classLoader.getResource(resourceName); - InputStream inputStream = null; - Writer writer = new StringWriter(); - String resourceContent = EMPTY; - if (resource != null) { - try { - inputStream = resource.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); - String line = reader.readLine(); - while (line != null) { - writer.write(line); - line = reader.readLine(); - } - resourceContent = writer.toString(); - - } catch (Exception e) { - logger.log(Level.WARNING, "There was an error loading an external resource", e); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "There was an error closing input stream", e); - } - try { - writer.close(); - } catch (IOException e) { - logger.log(Level.SEVERE, "There was an error closing writer", e); - } - } - } - return resourceContent; - } -} diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletMockWebServer.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletMockWebServer.java deleted file mode 100644 index 21cd2ae99..000000000 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletMockWebServer.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.hyperwallet.android.ui.transfermethod.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.IOException; -import java.net.HttpURLConnection; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; - -public final class HyperwalletMockWebServer extends TestWatcher { - - private MockWebServer mServer; - private int port; - - public HyperwalletMockWebServer(int port) { - this.port = port; - } - - @Override - protected void starting(Description description) { - super.starting(description); - mServer = new MockWebServer(); - try { - mServer.start(port); - } catch (IOException e) { - throw new IllegalStateException("Unable to start mock server", e); - } - } - - @Override - protected void finished(Description description) { - super.finished(description); - try { - mServer.shutdown(); - mServer.close(); - } catch (IOException e) { - throw new IllegalStateException("Un error occurred when shutting down mock server", e); - } - } - - public HyperwalletMockResponse mockResponse() { - return new Builder(mServer).build(); - } - - public MockWebServer getServer() { - return mServer; - } - - public static class HyperwalletMockResponse { - - private String path; - private String body; - private int httpResponseCode; - private Builder builder; - - HyperwalletMockResponse(Builder builder) { - this.path = builder.path; - this.httpResponseCode = builder.responseCode; - this.body = builder.body; - this.builder = builder; - } - - public HyperwalletMockResponse withHttpResponseCode(final int code) { - builder.responseCode(code); - return builder.build(); - } - - public HyperwalletMockResponse withBody(final String body) { - builder.body(body); - return builder.build(); - } - - public void mock() { - mockRequest(); - } - - private String mockRequest() { - builder.server.enqueue(new MockResponse().setResponseCode(httpResponseCode).setBody(body)); - return builder.server.url(path).toString(); - } - - } - - private static class Builder { - - private String path; - private String body; - private int responseCode; - private MockWebServer server; - - - Builder(final MockWebServer server) { - this.path = ""; - this.responseCode = HttpURLConnection.HTTP_OK; - this.body = ""; - this.server = server; - } - - Builder responseCode(final int code) { - this.responseCode = code; - return this; - } - - Builder body(final String body) { - this.body = body; - return this; - } - - HyperwalletMockResponse build() { - return new HyperwalletMockResponse(this); - } - } -} diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/EspressoUtils.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/EspressoUtils.java deleted file mode 100644 index fbd325c31..000000000 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/EspressoUtils.java +++ /dev/null @@ -1,187 +0,0 @@ -package com.hyperwallet.android.ui.transfermethod.util; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.view.View; -import android.widget.EditText; -import android.widget.ImageView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; -import androidx.test.espresso.ViewAction; -import androidx.test.espresso.action.ViewActions; -import androidx.test.espresso.matcher.BoundedMatcher; - -import com.google.android.material.textfield.TextInputLayout; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -import java.util.Objects; - -public class EspressoUtils { - - public static Matcher withHint(final String expectedHint) { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof TextInputLayout)) { - return false; - } - - String hint = Objects.toString(((TextInputLayout) view).getHint()); - return expectedHint.equals(hint); - } - - @Override - public void describeTo(Description description) { - description.appendText(expectedHint); - } - }; - } - - public static Matcher hasErrorText(final String expectedErrorMessage) { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof TextInputLayout)) { - return false; - } - - String errorMessage = Objects.toString(((TextInputLayout) view).getError()); - return expectedErrorMessage.equals(errorMessage); - } - - @Override - public void describeTo(Description description) { - description.appendText(expectedErrorMessage); - } - }; - } - - public static Matcher hasErrorText(final int resourceId) { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof TextInputLayout)) { - return false; - } - String expectedErrorMessage = view.getResources().getString(resourceId); - String errorMessage = Objects.toString(((TextInputLayout) view).getError()); - - return expectedErrorMessage.equals(errorMessage); - } - - @Override - public void describeTo(Description description) { - } - }; - } - - public static Matcher withDrawable(final int resourceId) { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof ImageView)) { - return false; - } - - Drawable drawable = ((ImageView) view).getDrawable(); - if (drawable == null) { - return false; - } - Drawable expectedDrawable = view.getContext().getResources().getDrawable(resourceId); - - Bitmap bitmap = getBitmap(drawable); - Bitmap expectedBitmap = getBitmap(expectedDrawable); - - return bitmap.sameAs(expectedBitmap); - } - - @Override - public void describeTo(Description description) { - } - }; - } - - public static Matcher atPosition(final int position, @NonNull final Matcher matcher) { - return new BoundedMatcher(RecyclerView.class) { - - @Override - protected boolean matchesSafely(final RecyclerView view) { - RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(position); - - if (viewHolder == null) { - return false; - } - - return matcher.matches(viewHolder.itemView); - } - - @Override - public void describeTo(Description description) { - description.appendText("has item at position " + position + ": "); - matcher.describeTo(description); - } - }; - } - - public static ViewAction nestedScrollTo() { - return ViewActions.actionWithAssertions(new NestedScrollToAction()); - } - - private static Bitmap getBitmap(Drawable drawable) { - Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - - Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - - return bitmap; - } - - public static Matcher hasNoErrorText() { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof TextInputLayout)) { - return false; - } - return ((TextInputLayout) view).getError() == null; - } - - @Override - public void describeTo(Description description) { - description.appendText("has no error text: "); - } - }; - } - - public static Matcher hasEmptyText() { - return new TypeSafeMatcher() { - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof EditText)) { - return false; - } - String text = ((EditText) view).getText().toString(); - - return text.isEmpty(); - } - - @Override - public void describeTo(Description description) { - } - }; - } -} - diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/NestedScrollToAction.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/NestedScrollToAction.java deleted file mode 100644 index 63a6803f7..000000000 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/NestedScrollToAction.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.hyperwallet.android.ui.transfermethod.util; - -import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; -import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; -import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; - -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anyOf; - -import android.view.View; - -import androidx.core.widget.NestedScrollView; -import androidx.test.espresso.UiController; -import androidx.test.espresso.ViewAction; -import androidx.test.espresso.action.ScrollToAction; -import androidx.test.espresso.matcher.ViewMatchers; - -import org.hamcrest.Matcher; - -public class NestedScrollToAction implements ViewAction { - private static final String TAG = ScrollToAction.class.getSimpleName(); - - @SuppressWarnings("unchecked") - @Override - public Matcher getConstraints() { - return allOf( - withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), - isDescendantOfA( - anyOf(isAssignableFrom(NestedScrollView.class)))); - } - - @Override - public void perform(UiController uiController, View view) { - new ScrollToAction().perform(uiController, view); - } - - @Override - public String getDescription() { - return "scroll to"; - } -} diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/RecyclerViewCountAssertion.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/RecyclerViewCountAssertion.java deleted file mode 100644 index 1c9ec2479..000000000 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/RecyclerViewCountAssertion.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.hyperwallet.android.ui.transfermethod.util; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -import android.view.View; - -import androidx.recyclerview.widget.RecyclerView; -import androidx.test.espresso.NoMatchingViewException; -import androidx.test.espresso.ViewAssertion; - -public class RecyclerViewCountAssertion implements ViewAssertion { - private final int mCount; - - public RecyclerViewCountAssertion(int count) { - this.mCount = count; - } - - @Override - public void check(View view, NoMatchingViewException noViewFoundException) { - if (noViewFoundException != null) { - throw noViewFoundException; - } - - RecyclerView recyclerView = (RecyclerView) view; - RecyclerView.Adapter adapter = recyclerView.getAdapter(); - - assertThat(adapter.getItemCount(), is(mCount)); - } -} diff --git a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/TestAuthenticationProvider.java b/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/TestAuthenticationProvider.java deleted file mode 100644 index 739423e40..000000000 --- a/transfermethodui/src/androidTest/java/com/hyperwallet/android/ui/transfermethod/util/TestAuthenticationProvider.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.hyperwallet.android.ui.transfermethod.util; - -import com.hyperwallet.android.HyperwalletAuthenticationTokenListener; -import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; - -import java.io.IOException; -import java.text.MessageFormat; -import java.util.UUID; - -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; - -public class TestAuthenticationProvider implements HyperwalletAuthenticationTokenProvider { - - public static final MediaType JSON - = MediaType.get("application/json; charset=utf-8"); - private static final String mBaseUrl = "http://localhost:8080/rest/v3/users/{0}/authentication-token"; - private static final String mUserToken = "user_token"; - - @Override - public void retrieveAuthenticationToken(final HyperwalletAuthenticationTokenListener authenticationTokenListener) { - - OkHttpClient client = new OkHttpClient(); - - String payload = "{}"; - String baseUrl = MessageFormat.format(mBaseUrl, mUserToken); - - RequestBody body = RequestBody.create(JSON, payload); - Request request = new Request.Builder() - .url(baseUrl) - .post(body) - .build(); - - client.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(Call call, IOException e) { - authenticationTokenListener.onFailure(UUID.randomUUID(), e.getMessage()); - } - - @Override - public void onResponse(Call call, Response response) throws IOException { - authenticationTokenListener.onSuccess(response.body().string()); - } - }); - } -} diff --git a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java b/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java index 42fcbb957..8e7dafb86 100644 --- a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java +++ b/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/AddTransferMethodPresenterTest.java @@ -24,9 +24,9 @@ import com.hyperwallet.android.model.graphql.field.HyperwalletTransferMethodConfiguration; import com.hyperwallet.android.model.transfermethod.HyperwalletBankAccount; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodConfigurationRepository; import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepository; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodContract; import com.hyperwallet.android.ui.transfermethod.view.AddTransferMethodPresenter; diff --git a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java b/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java index 13448a52f..cb61d4c53 100644 --- a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java +++ b/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/FeeFormatterTest.java @@ -10,7 +10,7 @@ import com.hyperwallet.android.model.graphql.HyperwalletFee; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.transfermethod.view.FeeFormatter; import org.json.JSONException; diff --git a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java b/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java index 588205dce..64356c2ac 100644 --- a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java +++ b/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/SelectTransferMethodPresenterTest.java @@ -21,9 +21,9 @@ import com.hyperwallet.android.model.graphql.keyed.HyperwalletTransferMethodConfigurationKeyResult; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.model.user.HyperwalletUser; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodConfigurationRepository; import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodConfigurationRepositoryImpl; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.transfermethod.view.SelectTransferMethodContract; import com.hyperwallet.android.ui.transfermethod.view.SelectTransferMethodPresenter; import com.hyperwallet.android.ui.transfermethod.view.TransferMethodSelectionItem; diff --git a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java b/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java index 839abf371..005e47450 100644 --- a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java +++ b/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java @@ -24,7 +24,7 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.model.transfermethod.PayPalAccount; import com.hyperwallet.android.ui.R; -import com.hyperwallet.android.ui.transfermethod.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; import com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils; import org.hamcrest.CoreMatchers; diff --git a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java b/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java deleted file mode 100644 index 4db98b20a..000000000 --- a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/rule/HyperwalletExternalResourceManager.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.hyperwallet.android.ui.transfermethod.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class HyperwalletExternalResourceManager extends TestWatcher { - - private static final String EMPTY = ""; - private ClassLoader classLoader; - private Logger logger; - - @Override - protected void starting(Description description) { - super.starting(description); - classLoader = description.getTestClass().getClassLoader(); - logger = Logger.getLogger(description.getTestClass().getName()); - } - - - public String getResourceContent(final String resourceName) { - if (resourceName == null) { - throw new IllegalArgumentException("Parameter resourceName cannot be null"); - } - - return getContent(resourceName); - } - - private String getContent(final String resourceName) { - - URL resource = classLoader.getResource(resourceName); - InputStream inputStream = null; - Writer writer = new StringWriter(); - String resourceContent = EMPTY; - if (resource != null) { - try { - inputStream = resource.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); - String line = reader.readLine(); - while (line != null) { - writer.write(line); - line = reader.readLine(); - } - resourceContent = writer.toString(); - - } catch (Exception e) { - logger.log(Level.WARNING, "There was an error loading an external resource", e); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "There was an error closing input stream", e); - } - try { - writer.close(); - } catch (IOException e) { - logger.log(Level.SEVERE, "There was an error closing writer", e); - } - } - } - return resourceContent; - } -} diff --git a/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java b/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java deleted file mode 100644 index d25311f64..000000000 --- a/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.hyperwallet.android.ui.transfer.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class HyperwalletExternalResourceManager extends TestWatcher { - - private static final String EMPTY = ""; - private ClassLoader classLoader; - private Logger logger; - - @Override - protected void starting(Description description) { - super.starting(description); - classLoader = description.getTestClass().getClassLoader(); - logger = Logger.getLogger(description.getTestClass().getName()); - } - - public String getResourceContent(final String resourceName) { - if (resourceName == null) { - throw new IllegalArgumentException("Parameter resourceName cannot be null"); - } - - return getContent(resourceName); - } - - private String getContent(final String resourceName) { - URL resource = classLoader.getResource(resourceName); - InputStream inputStream = null; - Writer writer = new StringWriter(); - String resourceContent = EMPTY; - if (resource != null) { - try { - inputStream = resource.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); - String line = reader.readLine(); - while (line != null) { - writer.write(line); - line = reader.readLine(); - } - resourceContent = writer.toString(); - - } catch (Exception e) { - logger.log(Level.WARNING, "There was an error loading an external resource", e); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "There was an error closing input stream", e); - } - try { - writer.close(); - } catch (IOException e) { - logger.log(Level.SEVERE, "There was an error closing writer", e); - } - } - } - return resourceContent; - } -} diff --git a/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java b/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java deleted file mode 100644 index b5a463e9c..000000000 --- a/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/rule/HyperwalletExternalResourceManager.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.hyperwallet.android.ui.transfer.rule; - -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class HyperwalletExternalResourceManager extends TestWatcher { - - private static final String EMPTY = ""; - private ClassLoader classLoader; - private Logger logger; - - @Override - protected void starting(Description description) { - super.starting(description); - classLoader = description.getTestClass().getClassLoader(); - logger = Logger.getLogger(description.getTestClass().getName()); - } - - public String getResourceContent(final String resourceName) { - if (resourceName == null) { - throw new IllegalArgumentException("Parameter resourceName cannot be null"); - } - - return getContent(resourceName); - } - - private String getContent(final String resourceName) { - URL resource = classLoader.getResource(resourceName); - InputStream inputStream = null; - Writer writer = new StringWriter(); - String resourceContent = EMPTY; - if (resource != null) { - try { - inputStream = resource.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); - String line = reader.readLine(); - while (line != null) { - writer.write(line); - line = reader.readLine(); - } - resourceContent = writer.toString(); - - } catch (Exception e) { - logger.log(Level.WARNING, "There was an error loading an external resource", e); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "There was an error closing input stream", e); - } - try { - writer.close(); - } catch (IOException e) { - logger.log(Level.SEVERE, "There was an error closing writer", e); - } - } - } - return resourceContent; - } -} From 56a7004860b79b0e0122bac37bf604ee8d02ed39 Mon Sep 17 00:00:00 2001 From: Shyang Koong Date: Tue, 6 Aug 2019 11:34:37 -0700 Subject: [PATCH 035/177] Adding missing label ids (#87) --- transfermethodui/src/main/res/values/ids.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/transfermethodui/src/main/res/values/ids.xml b/transfermethodui/src/main/res/values/ids.xml index 11c5195a9..fe735da83 100644 --- a/transfermethodui/src/main/res/values/ids.xml +++ b/transfermethodui/src/main/res/values/ids.xml @@ -79,7 +79,9 @@ + + From c4ac1ab6d4c258d8854478246e4b15fa8545e283 Mon Sep 17 00:00:00 2001 From: Peter Joseph Olamit Date: Thu, 8 Aug 2019 17:42:10 -0700 Subject: [PATCH 036/177] HW-53670 create transfer (#81) --- commonui/build.gradle | 5 + .../ui/common/view/OneClickListener.java | 1 - .../ui/common}/view/TransferMethodUtils.java | 4 +- commonui/src/main/res/values/strings.xml | 18 + commonui/src/main/res/values/styles.xml | 4 + .../common/view}/TransferMethodUtilsTest.java | 20 +- .../test/resources/bank_card_response.json | 20 + .../repository/TransferMethodRepository.java | 14 +- .../TransferMethodRepositoryImpl.java | 37 ++ .../TransferMethodRepositoryImplTest.java | 84 ++++ .../view/AddTransferMethodActivity.java | 1 + .../view/ListTransferMethodFragment.java | 6 +- .../view/SelectTransferMethodFragment.java | 2 +- .../src/main/res/values/strings.xml | 18 - transferrepository/build.gradle | 1 + .../repository/TransferRepository.java | 97 +++++ .../repository/TransferRepositoryFactory.java | 53 +++ .../repository/TransferRepositoryImpl.java | 97 +++++ .../TransferRepositoryFactoryTest.java | 38 ++ .../TransferRepositoryImplTest.java | 234 +++++++++++ .../resources/transfer_error_response.json | 8 + .../transfer_schedule_error_response.json | 8 + .../transfer_scheduled_success_response.json | 16 + .../resources/transfer_success_response.json | 23 + transferui/build.gradle | 20 +- transferui/config/jacoco-settings.gradle | 0 transferui/config/lint.xml | 8 + .../src/androidTest/AndroidManifest.xml | 10 + ...yperwalletInstrumentedTestApplication.java | 31 ++ .../ui/transfer/SelectDestinationTest.java | 214 ++++++++++ .../ui/transfer/TransferUserFundsTest.java | 167 ++++++++ transferui/src/main/AndroidManifest.xml | 24 +- .../ui/transfer/HyperwalletTransferUi.java | 15 +- .../transfer/view/CreateTransferActivity.java | 140 +++++++ .../transfer/view/CreateTransferFragment.java | 395 ++++++++++++++++++ .../view/ListTransferDestinationActivity.java | 133 ++++++ .../view/ListTransferDestinationFragment.java | 280 +++++++++++++ .../viewmodel/CreateTransferViewModel.java | 344 +++++++++++++++ .../ListTransferDestinationViewModel.java | 109 +++++ .../res/layout/activity_create_transfer.xml | 41 ++ .../activity_list_transfer_destination.xml | 17 + ...log_fragment_list_transfer_destination.xml | 56 +++ .../res/layout/fragment_create_transfer.xml | 249 +++++++++++ .../res/layout/item_transfer_destination.xml | 81 ++++ .../widget_add_transfer_destination.xml | 62 +++ .../layout/widget_transfer_destination.xml | 76 ++++ transferui/src/main/res/values/dimension.xml | 6 + transferui/src/main/res/values/strings.xml | 24 ++ transferui/src/main/res/values/styles.xml | 10 + .../main/res/xml/network_security_config.xml | 6 + .../CreateTransferViewModelTest.java | 362 ++++++++++++++++ .../ListTransferDestinationViewModelTest.java | 96 +++++ .../authentication_token_response.json | 3 + ...create_transfer_paypal_quote_response.json | 25 ++ .../create_transfer_quote_response.json | 25 ++ .../resources/transfer_error_response.json | 8 + .../transfer_method_list_response.json | 188 +++++++++ ...hod_list_single_bank_account_response.json | 51 +++ .../src/test/resources/user_response.json | 26 ++ 59 files changed, 4070 insertions(+), 41 deletions(-) rename {transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod => commonui/src/main/java/com/hyperwallet/android/ui/common}/view/TransferMethodUtils.java (98%) rename {transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod => commonui/src/test/java/com/hyperwallet/android/ui/common/view}/TransferMethodUtilsTest.java (92%) create mode 100644 commonui/src/test/resources/bank_card_response.json create mode 100644 transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepository.java create mode 100644 transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryFactory.java create mode 100644 transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryImpl.java create mode 100644 transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryFactoryTest.java create mode 100644 transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryImplTest.java create mode 100644 transferrepository/src/test/resources/transfer_error_response.json create mode 100644 transferrepository/src/test/resources/transfer_schedule_error_response.json create mode 100644 transferrepository/src/test/resources/transfer_scheduled_success_response.json create mode 100644 transferrepository/src/test/resources/transfer_success_response.json create mode 100644 transferui/config/jacoco-settings.gradle create mode 100644 transferui/src/androidTest/AndroidManifest.xml create mode 100644 transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/HyperwalletInstrumentedTestApplication.java create mode 100644 transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/SelectDestinationTest.java create mode 100644 transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/TransferUserFundsTest.java create mode 100644 transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/CreateTransferActivity.java create mode 100644 transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/CreateTransferFragment.java create mode 100644 transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/ListTransferDestinationActivity.java create mode 100644 transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/ListTransferDestinationFragment.java create mode 100644 transferui/src/main/java/com/hyperwallet/android/ui/transfer/viewmodel/CreateTransferViewModel.java create mode 100644 transferui/src/main/java/com/hyperwallet/android/ui/transfer/viewmodel/ListTransferDestinationViewModel.java create mode 100644 transferui/src/main/res/layout/activity_create_transfer.xml create mode 100644 transferui/src/main/res/layout/activity_list_transfer_destination.xml create mode 100644 transferui/src/main/res/layout/dialog_fragment_list_transfer_destination.xml create mode 100644 transferui/src/main/res/layout/fragment_create_transfer.xml create mode 100644 transferui/src/main/res/layout/item_transfer_destination.xml create mode 100644 transferui/src/main/res/layout/widget_add_transfer_destination.xml create mode 100644 transferui/src/main/res/layout/widget_transfer_destination.xml create mode 100644 transferui/src/main/res/values/dimension.xml create mode 100644 transferui/src/main/res/values/strings.xml create mode 100644 transferui/src/main/res/values/styles.xml create mode 100644 transferui/src/main/res/xml/network_security_config.xml create mode 100644 transferui/src/test/java/com/hyperwallet/android/ui/transfer/viewmodel/CreateTransferViewModelTest.java create mode 100644 transferui/src/test/java/com/hyperwallet/android/ui/transfer/viewmodel/ListTransferDestinationViewModelTest.java create mode 100644 transferui/src/test/resources/authentication_token_response.json create mode 100644 transferui/src/test/resources/create_transfer_paypal_quote_response.json create mode 100644 transferui/src/test/resources/create_transfer_quote_response.json create mode 100644 transferui/src/test/resources/transfer_error_response.json create mode 100644 transferui/src/test/resources/transfer_method_list_response.json create mode 100644 transferui/src/test/resources/transfer_method_list_single_bank_account_response.json create mode 100644 transferui/src/test/resources/user_response.json diff --git a/commonui/build.gradle b/commonui/build.gradle index 5b1152d33..c88b2d219 100644 --- a/commonui/build.gradle +++ b/commonui/build.gradle @@ -3,6 +3,7 @@ project.ext { fileFilter = ['**/BuildConfig.*', '**/com/hyperwallet/android/ui/common/view/error/DefaultErrorDialogFragment.*', '**/com/hyperwallet/android/ui/common/view/HorizontalDividerItemDecorator.*', + '**/com/hyperwallet/android/ui/common/view/TransferMethodUtils.*', '**/com/hyperwallet/android/ui/common/view/OneClickListener.*' ] } @@ -13,4 +14,8 @@ apply from: "$rootProject.projectDir/publish.gradle" dependencies { implementation project(':commonrepository') + + testImplementation "org.robolectric:robolectric:$robolectricVersion" + + testImplementation project(':testutils') } \ No newline at end of file diff --git a/commonui/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java index e5822917b..eb73c70ca 100644 --- a/commonui/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java +++ b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/OneClickListener.java @@ -44,4 +44,3 @@ public void onClick(View v) { */ public abstract void onOneClick(View v); } - diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/TransferMethodUtils.java b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/TransferMethodUtils.java similarity index 98% rename from transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/TransferMethodUtils.java rename to commonui/src/main/java/com/hyperwallet/android/ui/common/view/TransferMethodUtils.java index 28582f9ec..ab2abec0a 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/TransferMethodUtils.java +++ b/commonui/src/main/java/com/hyperwallet/android/ui/common/view/TransferMethodUtils.java @@ -14,7 +14,7 @@ * 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.view; +package com.hyperwallet.android.ui.common.view; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.BANK_ACCOUNT_ID; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.CARD_NUMBER; @@ -36,7 +36,7 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodType; -import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.R; import java.util.Locale; diff --git a/commonui/src/main/res/values/strings.xml b/commonui/src/main/res/values/strings.xml index f46ffb1a3..65c4654e2 100644 --- a/commonui/src/main/res/values/strings.xml +++ b/commonui/src/main/res/values/strings.xml @@ -5,5 +5,23 @@ Cancel Close Try again + Not Available + + Bank Account + Debit Card + Wire Transfer + Paper Check + Prepaid Card + PayPal Account + + \uE000 + \uE005 + \uE00D + \uE002 + \uE00A + \uE021 + + Ending on %s + (not translated) diff --git a/commonui/src/main/res/values/styles.xml b/commonui/src/main/res/values/styles.xml index 076d3a7d1..0f8655681 100644 --- a/commonui/src/main/res/values/styles.xml +++ b/commonui/src/main/res/values/styles.xml @@ -236,6 +236,10 @@ + + diff --git a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java b/commonui/src/test/java/com/hyperwallet/android/ui/common/view/TransferMethodUtilsTest.java similarity index 92% rename from transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java rename to commonui/src/test/java/com/hyperwallet/android/ui/common/view/TransferMethodUtilsTest.java index 005e47450..e737d9314 100644 --- a/transfermethodui/src/test/java/com/hyperwallet/android/ui/transfermethod/TransferMethodUtilsTest.java +++ b/commonui/src/test/java/com/hyperwallet/android/ui/common/view/TransferMethodUtilsTest.java @@ -1,4 +1,4 @@ -package com.hyperwallet.android.ui.transfermethod; +package com.hyperwallet.android.ui.common.view; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -14,7 +14,7 @@ import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.BANK_CARD; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.PAPER_CHECK; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT; -import static com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils.getTransferMethodDetail; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getTransferMethodDetail; import android.content.Context; import android.content.res.Resources; @@ -23,17 +23,16 @@ import com.hyperwallet.android.model.transfermethod.HyperwalletBankCard; import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; import com.hyperwallet.android.model.transfermethod.PayPalAccount; -import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.R; import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; -import com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils; -import org.hamcrest.CoreMatchers; import org.json.JSONException; import org.json.JSONObject; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -159,7 +158,8 @@ public void getTransferMethodDetail_returnsCardDetails() { HyperwalletTransferMethod transferMethod = new HyperwalletBankCard.Builder().cardNumber( "************0006").build(); - when(mContext.getString(eq(R.string.transfer_method_list_item_description), eq("0006"))).thenReturn( + when(mContext.getString(ArgumentMatchers.eq(R.string.transfer_method_list_item_description), + eq("0006"))).thenReturn( "Ending on 0006"); String actual = getTransferMethodDetail(mContext, transferMethod, BANK_CARD); assertThat(actual, is("Ending on 0006")); @@ -170,7 +170,8 @@ public void getTransferMethodDetail_returnsBankAccountDetails() { HyperwalletTransferMethod transferMethod = new HyperwalletBankAccount.Builder().bankAccountId( "8017110254").build(); - when(mContext.getString(eq(R.string.transfer_method_list_item_description), eq("0254"))).thenReturn( + when(mContext.getString(ArgumentMatchers.eq(R.string.transfer_method_list_item_description), + eq("0254"))).thenReturn( "Ending on 0254"); String actual = getTransferMethodDetail(mContext, transferMethod, BANK_ACCOUNT); assertThat(actual, is("Ending on 0254")); @@ -181,7 +182,8 @@ public void getTransferMethodDetail_returnsPaperCheckDetails() { HyperwalletTransferMethod transferMethod = new HyperwalletTransferMethod(); String actual = getTransferMethodDetail(mContext, transferMethod, PAPER_CHECK); - assertThat(actual, CoreMatchers.is("")); - verify(mContext, never()).getString(eq(R.string.transfer_method_list_item_description), anyString()); + assertThat(actual, is("")); + verify(mContext, never()).getString(ArgumentMatchers.eq(R.string.transfer_method_list_item_description), + anyString()); } } diff --git a/commonui/src/test/resources/bank_card_response.json b/commonui/src/test/resources/bank_card_response.json new file mode 100644 index 000000000..946936b24 --- /dev/null +++ b/commonui/src/test/resources/bank_card_response.json @@ -0,0 +1,20 @@ +{ + "token": "trm-d8c65e1e-b3e5-460d-8b24-bee7cdae1636", + "type": "BANK_CARD", + "status": "ACTIVATED", + "createdOn": "2019-01-08T00:56:15", + "transferMethodCountry": "US", + "transferMethodCurrency": "USD", + "cardType": "DEBIT", + "cardNumber": "************0006", + "cardBrand": "VISA", + "dateOfExpiry": "2020-10", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-83cc9055-e7ee-489e-8fba-3af260cd709c/bank-cards/trm-d8c65e1e-b3e5-460d-8b24-bee7cdae1636" + } + ] +} \ No newline at end of file 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 93e057de1..4cc8f71c5 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 @@ -17,6 +17,7 @@ package com.hyperwallet.android.ui.transfermethod.repository; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.hyperwallet.android.model.HyperwalletErrors; import com.hyperwallet.android.model.StatusTransition; @@ -39,12 +40,19 @@ void createTransferMethod(@NonNull HyperwalletTransferMethod transferMethod, @NonNull LoadTransferMethodCallback callback); /** - * Load transfer methods available associated with current context + * Load transfer methods available, associated with current context * * @param callback @see {@link LoadTransferMethodListCallback} */ void loadTransferMethods(@NonNull LoadTransferMethodListCallback callback); + /** + * Load latest transfer methods available, associated with current context + * + * @param callback @see {@link LoadTransferMethodListCallback} + */ + void loadLatestTransferMethod(@NonNull LoadTransferMethodCallback callback); + /** * Deactivate transfer method specified. * @@ -65,7 +73,7 @@ void deactivateTransferMethod(@NonNull final HyperwalletTransferMethod transferM */ interface LoadTransferMethodCallback { - void onTransferMethodLoaded(HyperwalletTransferMethod transferMethod); + void onTransferMethodLoaded(@Nullable HyperwalletTransferMethod transferMethod); void onError(HyperwalletErrors errors); } @@ -76,7 +84,7 @@ interface LoadTransferMethodCallback { */ interface LoadTransferMethodListCallback { - void onTransferMethodListLoaded(List transferMethods); + void onTransferMethodListLoaded(@Nullable List transferMethods); void onError(HyperwalletErrors errors); } 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 a7596bce0..d5787fb33 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 @@ -50,6 +50,9 @@ Hyperwallet getHyperwallet() { return Hyperwallet.getDefault(); } + /** + * @see TransferMethodRepository#createTransferMethod(HyperwalletTransferMethod, LoadTransferMethodCallback) + */ @Override public void createTransferMethod(@NonNull final HyperwalletTransferMethod transferMethod, LoadTransferMethodCallback callback) { @@ -68,6 +71,9 @@ public void createTransferMethod(@NonNull final HyperwalletTransferMethod transf } } + /** + * @see TransferMethodRepository#loadLatestTransferMethod(LoadTransferMethodCallback) + */ @Override public void loadTransferMethods(@NonNull final LoadTransferMethodListCallback callback) { @@ -93,6 +99,37 @@ public Handler getHandler() { }); } + /** + * @see TransferMethodRepository#loadLatestTransferMethod(LoadTransferMethodCallback) + */ + @Override + public void loadLatestTransferMethod(@NonNull final LoadTransferMethodCallback callback) { + HyperwalletTransferMethodQueryParam queryParam = new HyperwalletTransferMethodQueryParam.Builder() + .limit(1) + .status(ACTIVATED) + .build(); + getHyperwallet().listTransferMethods(queryParam, + new HyperwalletListener>() { + @Override + public void onSuccess(@Nullable HyperwalletPageList result) { + callback.onTransferMethodLoaded(result != null ? result.getDataList().get(0) : null); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getHyperwalletErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + + /** + * @see TransferMethodRepository#deactivateTransferMethod(HyperwalletTransferMethod, DeactivateTransferMethodCallback) + */ @Override public void deactivateTransferMethod(@NonNull final HyperwalletTransferMethod transferMethod, @NonNull final DeactivateTransferMethodCallback callback) { diff --git a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java index 6d7f91f17..6f1a19d3a 100644 --- a/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java +++ b/transfermethodrepository/src/test/java/com/hyperwallet/android/ui/transfermethod/repository/TransferMethodRepositoryImplTest.java @@ -491,6 +491,90 @@ public Object answer(InvocationOnMock invocation) { assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); } + @Test + public void testLoadLatestTransferMethod_returnsBankAccount() { + List accounts = new ArrayList() {{ + add(new HyperwalletBankAccount + .Builder("CA", "CAD", "3423423432") + .build()); + add(new HyperwalletBankAccount + .Builder("US", "USD", "1231231222") + .build()); + }}; + + final HyperwalletPageList pageList = new HyperwalletPageList<>(accounts); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onSuccess(pageList); + return listener; + } + }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodQueryParam) any(), + ArgumentMatchers.>>any()); + + // test + mTransferMethodRepository.loadLatestTransferMethod(mLoadTransferMethodCallback); + + verify(mLoadTransferMethodCallback).onTransferMethodLoaded(mBankAccountArgumentCaptor.capture()); + verify(mLoadTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); + + HyperwalletBankAccount transferMethod = mBankAccountArgumentCaptor.getValue(); + assertThat(transferMethod, is(notNullValue())); + assertThat(transferMethod.getField(TRANSFER_METHOD_COUNTRY), is("CA")); + assertThat(transferMethod.getField(TRANSFER_METHOD_CURRENCY), is("CAD")); + assertThat(transferMethod.getField(BANK_ACCOUNT_ID), is("3423423432")); + } + + @Test + public void testLoadLatestTransferMethod_returnsNoAccounts() { + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + listener.onSuccess(null); + return listener; + } + }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodQueryParam) any(), + ArgumentMatchers.>>any()); + + // test + mTransferMethodRepository.loadLatestTransferMethod(mLoadTransferMethodCallback); + + verify(mLoadTransferMethodCallback).onTransferMethodLoaded(mBankAccountArgumentCaptor.capture()); + verify(mLoadTransferMethodCallback, never()).onError(any(HyperwalletErrors.class)); + + HyperwalletBankAccount transferMethod = mBankAccountArgumentCaptor.getValue(); + assertThat(transferMethod, is(nullValue())); + } + + @Test + public void testLoadLatestTransferMethod_withError() { + final HyperwalletError error = new HyperwalletError("test message", "TEST_CODE"); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = (HyperwalletListener) invocation.getArguments()[1]; + List errorList = new ArrayList<>(); + errorList.add(error); + HyperwalletErrors errors = new HyperwalletErrors(errorList); + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).listTransferMethods((HyperwalletTransferMethodQueryParam) any(), + ArgumentMatchers.>>any()); + + // test + mTransferMethodRepository.loadLatestTransferMethod(mLoadTransferMethodCallback); + + verify(mLoadTransferMethodCallback, never()).onTransferMethodLoaded(any(HyperwalletTransferMethod.class)); + verify(mLoadTransferMethodCallback).onError(mErrorsArgumentCaptor.capture()); + + assertThat(mErrorsArgumentCaptor.getValue().getErrors(), hasItem(error)); + } + @Test public void testCreateTransferMethod_payPalAccountWithSuccess() { // prepare diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodActivity.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodActivity.java index e3ba27b72..50ef5ca37 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodActivity.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/AddTransferMethodActivity.java @@ -30,6 +30,7 @@ import com.hyperwallet.android.model.HyperwalletError; import com.hyperwallet.android.ui.R; +import com.hyperwallet.android.ui.common.view.TransferMethodUtils; import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; import com.hyperwallet.android.ui.common.view.error.OnNetworkErrorCallback; 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 a1fb9d213..891ad5755 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 @@ -18,9 +18,9 @@ import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY; import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TYPE; -import static com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils.getStringFontIcon; -import static com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils.getStringResourceByName; -import static com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils.getTransferMethodDetail; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getStringFontIcon; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getStringResourceByName; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getTransferMethodDetail; import android.content.Context; import android.content.Intent; diff --git a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/SelectTransferMethodFragment.java b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/SelectTransferMethodFragment.java index 513be291f..a306071d9 100644 --- a/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/SelectTransferMethodFragment.java +++ b/transfermethodui/src/main/java/com/hyperwallet/android/ui/transfermethod/view/SelectTransferMethodFragment.java @@ -18,7 +18,7 @@ package com.hyperwallet.android.ui.transfermethod.view; -import static com.hyperwallet.android.ui.transfermethod.view.TransferMethodUtils.getStringFontIcon; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getStringFontIcon; import android.annotation.SuppressLint; import android.content.Context; diff --git a/transfermethodui/src/main/res/values/strings.xml b/transfermethodui/src/main/res/values/strings.xml index f77d5e91e..f80dac0f7 100644 --- a/transfermethodui/src/main/res/values/strings.xml +++ b/transfermethodui/src/main/res/values/strings.xml @@ -1,9 +1,7 @@ hyperwallet.ui Add Account - Not Available Unknown - (not translated) Select Transfer Method @@ -38,7 +36,6 @@ You didn\'t add an account yet. Once created, it will show up here! - Ending on %s Are you sure that you want to remove this account? @@ -61,21 +58,6 @@ %1$s %2$s + %3$s%% (Max:%1$s %4$s) %1$s %2$s + %3$s%% (Min:%1$s %4$s, Max:%1$s %5$s) - - Bank Account - Debit Card - Wire Transfer - Paper Check - Prepaid Card - PayPal Account - - \uE000 - \uE005 - \uE00D - \uE002 - \uE00A - \uE021 - Account Holder Account Information Address diff --git a/transferrepository/build.gradle b/transferrepository/build.gradle index dcd8fba0f..f26717936 100644 --- a/transferrepository/build.gradle +++ b/transferrepository/build.gradle @@ -11,4 +11,5 @@ dependencies { api project(':commonrepository') testImplementation "org.robolectric:robolectric:$robolectricVersion" + testImplementation project(':testutils') } \ No newline at end of file diff --git a/transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepository.java b/transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepository.java new file mode 100644 index 000000000..6459b7b46 --- /dev/null +++ b/transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepository.java @@ -0,0 +1,97 @@ +/* + * Copyright 2019 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.transfer.repository; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.StatusTransition; +import com.hyperwallet.android.model.transfer.Transfer; + +/** + * Transfer Repository + */ +public interface TransferRepository { + + /** + * Create Transfer + * + * @param transfer Transfer object {@link Transfer} + * @param callback Callback object invoked after processing {@link CreateTransferCallback} + */ + void createTransfer(@NonNull final Transfer transfer, @NonNull final CreateTransferCallback callback); + + /** + * Schedule Transfer + * + * @param transfer Transfer object {@link Transfer} + * @param callback Callback object invoked after processing {@link ScheduleTransferCallback} + */ + void scheduleTransfer(@NonNull final Transfer transfer, @NonNull final ScheduleTransferCallback callback); + + + /** + * Create Transfer Callback + */ + interface CreateTransferCallback { + + /** + * Callback method when Transfer is created successfully. + * + * @param transfer Transfer object {@link Transfer} + */ + void onTransferCreated(@Nullable final Transfer transfer); + + /** + * Callback method when error occur on Create Transfer action. + * + * @param errors Transfer error representation {@link HyperwalletErrors} + */ + void onError(@NonNull final HyperwalletErrors errors); + } + + /** + * Schedule Transfer Callback + */ + interface ScheduleTransferCallback { + + /** + * Callback method when Transfer is scheduled successfully. + * + * @param statusTransition Transfer object {@link StatusTransition} + */ + void onTransferScheduled(@Nullable final StatusTransition statusTransition); + + /** + * Callback method when error occur on Create Transfer action. + * + * @param errors Transfer error representation {@link HyperwalletErrors} + */ + void onError(@NonNull final HyperwalletErrors errors); + } +} diff --git a/transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryFactory.java b/transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryFactory.java new file mode 100644 index 000000000..931b78b70 --- /dev/null +++ b/transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019 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.transfer.repository; + +public class TransferRepositoryFactory { + + private static TransferRepositoryFactory sInstance; + + private TransferRepository mTransferRepository; + + private TransferRepositoryFactory() { + mTransferRepository = new TransferRepositoryImpl(); + } + + public synchronized static TransferRepositoryFactory getInstance() { + if (sInstance == null) { + sInstance = new TransferRepositoryFactory(); + } + return sInstance; + } + + public TransferRepository getTransferRepository() { + return mTransferRepository; + } + + public static void clearInstance() { + sInstance = null; + } +} diff --git a/transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryImpl.java b/transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryImpl.java new file mode 100644 index 000000000..ec57cad19 --- /dev/null +++ b/transferrepository/src/main/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryImpl.java @@ -0,0 +1,97 @@ +/* + * Copyright 2019 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.transfer.repository; + +import android.os.Handler; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.listener.HyperwalletListener; +import com.hyperwallet.android.model.StatusTransition; +import com.hyperwallet.android.model.transfer.Transfer; + +/** + * Transfer Repository Implementation + */ +public class TransferRepositoryImpl implements TransferRepository { + + private Handler mHandler = new Handler(); + + /** + * @see TransferRepository#createTransfer(Transfer, CreateTransferCallback) + */ + @Override + public void createTransfer(@NonNull final Transfer transfer, @NonNull final CreateTransferCallback callback) { + getHyperwallet().createTransfer(transfer, new HyperwalletListener() { + @Override + public void onSuccess(@Nullable Transfer result) { + callback.onTransferCreated(result); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getHyperwalletErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + + /** + * @see TransferRepository#scheduleTransfer(Transfer, ScheduleTransferCallback) + */ + @Override + public void scheduleTransfer(@NonNull final Transfer transfer, @NonNull final ScheduleTransferCallback callback) { + getHyperwallet().scheduleTransfer(transfer.getToken(), transfer.getNotes(), + new HyperwalletListener() { + @Override + public void onSuccess(@Nullable StatusTransition result) { + callback.onTransferScheduled(result); + } + + @Override + public void onFailure(HyperwalletException exception) { + callback.onError(exception.getHyperwalletErrors()); + } + + @Override + public Handler getHandler() { + return mHandler; + } + }); + } + + Hyperwallet getHyperwallet() { + return Hyperwallet.getDefault(); + } +} diff --git a/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryFactoryTest.java b/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryFactoryTest.java new file mode 100644 index 000000000..15557acb9 --- /dev/null +++ b/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryFactoryTest.java @@ -0,0 +1,38 @@ +package com.hyperwallet.android.ui.transfer.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; + +public class TransferRepositoryFactoryTest { + + @Test + public void testGetInstance_verifyRepositoryInitialized() { + TransferRepositoryFactory transferRepositoryFactory = TransferRepositoryFactory.getInstance(); + assertThat(transferRepositoryFactory, is(notNullValue())); + assertThat(transferRepositoryFactory.getTransferRepository(), is(notNullValue())); + } + + @Test + public void testClearInstance_verifyRepositoryCleared() { + TransferRepositoryFactory transferRepositoryFactory = TransferRepositoryFactory.getInstance(); + TransferRepository transferRepository = transferRepositoryFactory.getTransferRepository(); + + TransferRepositoryFactory transferRepositoryFactorySame = TransferRepositoryFactory.getInstance(); + TransferRepository transferRepositorySame = transferRepositoryFactorySame.getTransferRepository(); + + assertThat(transferRepositoryFactory, is(transferRepositoryFactory)); + assertThat(transferRepository, is(transferRepositorySame)); + + TransferRepositoryFactory.clearInstance(); + + transferRepositoryFactory = TransferRepositoryFactory.getInstance(); + transferRepository = transferRepositoryFactory.getTransferRepository(); + + assertThat(transferRepositoryFactory, is(not(transferRepositoryFactorySame))); + assertThat(transferRepository, is(not(transferRepositorySame))); + } +} diff --git a/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryImplTest.java b/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryImplTest.java new file mode 100644 index 000000000..1fc5cb025 --- /dev/null +++ b/transferrepository/src/test/java/com/hyperwallet/android/ui/transfer/repository/TransferRepositoryImplTest.java @@ -0,0 +1,234 @@ +package com.hyperwallet.android.ui.transfer.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import static com.hyperwallet.android.model.StatusTransition.StatusDefinition.QUOTED; +import static com.hyperwallet.android.model.StatusTransition.StatusDefinition.SCHEDULED; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.exception.HyperwalletException; +import com.hyperwallet.android.listener.HyperwalletListener; +import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.StatusTransition; +import com.hyperwallet.android.model.TypeReference; +import com.hyperwallet.android.model.transfer.Transfer; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.util.JsonUtils; + +import org.hamcrest.Matchers; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.stubbing.Answer; +import org.robolectric.RobolectricTestRunner; + +import java.util.Date; +import java.util.UUID; + +@RunWith(RobolectricTestRunner.class) +public class TransferRepositoryImplTest { + + @Rule + public MockitoRule mMockito = MockitoJUnit.rule(); + @Rule + public HyperwalletExternalResourceManager mResourceManager = new HyperwalletExternalResourceManager(); + @Mock + private Hyperwallet mHyperwallet; + @Mock + private TransferRepository.CreateTransferCallback mCreateTransferCallback; + @Mock + private TransferRepository.ScheduleTransferCallback mScheduleTransferCallback; + + @Captor + private ArgumentCaptor mStatusTransitionArgumentCaptor; + @Captor + private ArgumentCaptor mCreateTransferArgumentCaptor; + @Captor + private ArgumentCaptor mErrorsArgumentCaptor; + + @Spy + private TransferRepositoryImpl mTransferRepository; + + @Before + public void setUp() { + doReturn(mHyperwallet).when(mTransferRepository).getHyperwallet(); + } + + @Test + public void testCreateTransfer_onSuccess() throws JSONException { + String responseJson = mResourceManager.getResourceContent("transfer_success_response.json"); + JSONObject jsonObject = new JSONObject(responseJson); + final Transfer transfer = new Transfer(jsonObject); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = invocation.getArgument(1); + listener.onSuccess(transfer); + return listener; + } + }).when(mHyperwallet).createTransfer(any(Transfer.class), any(HyperwalletListener.class)); + + Transfer transferRequest = new Transfer.Builder() + .clientTransferID(UUID.randomUUID().toString()) + .createdOn(new Date()) + .destinationAmount("20.00") + .destinationCurrency("USD") + .destinationToken("trm-token") + .sourceToken("usr-token") + .build(); + + // test + mTransferRepository.createTransfer(transferRequest, mCreateTransferCallback); + + verify(mCreateTransferCallback).onTransferCreated(mCreateTransferArgumentCaptor.capture()); + verify(mCreateTransferCallback, never()).onError(any(HyperwalletErrors.class)); + + Transfer capturedTransfer = mCreateTransferArgumentCaptor.getValue(); + assertThat(capturedTransfer, is(notNullValue())); + assertThat(capturedTransfer.getStatus(), is(QUOTED)); + assertThat(capturedTransfer.getToken(), is("trf-token")); + assertThat(capturedTransfer.getDestinationToken(), is("trm-token")); + assertThat(capturedTransfer.getSourceToken(), is("usr-token")); + } + + @Test + public void testCreateTransfer_onFailure() throws Exception { + String errorResponse = mResourceManager.getResourceContent("transfer_error_response.json"); + final HyperwalletErrors errors = JsonUtils.fromJsonString(errorResponse, + new TypeReference() { + }); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = invocation.getArgument(1); + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).createTransfer(any(Transfer.class), any(HyperwalletListener.class)); + + Transfer transferRequest = new Transfer.Builder() + .clientTransferID(UUID.randomUUID().toString()) + .createdOn(new Date()) + .destinationAmount("20.00") + .destinationCurrency("USD") + .destinationToken("trm-token") + .sourceToken("usr-token") + .build(); + + // test + mTransferRepository.createTransfer(transferRequest, mCreateTransferCallback); + + verify(mCreateTransferCallback, never()).onTransferCreated(any(Transfer.class)); + verify(mCreateTransferCallback).onError(mErrorsArgumentCaptor.capture()); + + HyperwalletErrors capturedErrors = mErrorsArgumentCaptor.getValue(); + assertThat(capturedErrors, is(notNullValue())); + assertThat(capturedErrors.getErrors(), Matchers.hasSize(1)); + assertThat(capturedErrors.getErrors().get(0).getCode(), is("INVALID_SOURCE_TOKEN")); + assertThat(capturedErrors.getErrors().get(0).getMessage(), + is("The source token you provided doesn’t exist or is not a valid source.")); + } + + @Test + public void testScheduledTransfer_onSuccess() throws Exception { + String responseJson = mResourceManager.getResourceContent("transfer_scheduled_success_response.json"); + JSONObject jsonObject = new JSONObject(responseJson); + final StatusTransition statusTransition = new StatusTransition(jsonObject); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = invocation.getArgument(2); + listener.onSuccess(statusTransition); + return listener; + } + }).when(mHyperwallet).scheduleTransfer(anyString(), anyString(), any(HyperwalletListener.class)); + + Transfer transferRequest = new Transfer.Builder() + .clientTransferID(UUID.randomUUID().toString()) + .createdOn(new Date()) + .destinationAmount("20.00") + .destinationCurrency("USD") + .destinationToken("trm-token") + .sourceToken("usr-token") + .token("trf-token") + .notes("this is the notes") + .build(); + + // test + mTransferRepository.scheduleTransfer(transferRequest, mScheduleTransferCallback); + + verify(mScheduleTransferCallback).onTransferScheduled(mStatusTransitionArgumentCaptor.capture()); + verify(mScheduleTransferCallback, never()).onError(any(HyperwalletErrors.class)); + + StatusTransition scheduledTransition = mStatusTransitionArgumentCaptor.getValue(); + assertThat(scheduledTransition, is(notNullValue())); + assertThat(scheduledTransition.getToken(), is("sts-token")); + assertThat(scheduledTransition.getCreatedOn(), is("2019-07-23T15:20:17")); + assertThat(scheduledTransition.getTransition(), is(SCHEDULED)); + assertThat(scheduledTransition.getFromStatus(), is(QUOTED)); + assertThat(scheduledTransition.getToStatus(), is(SCHEDULED)); + assertThat(scheduledTransition.getNotes(), is("Completing the Partial-Balance Transfer")); + } + + @Test + public void testScheduledTransfer_onFailure() throws Exception { + String errorResponse = mResourceManager.getResourceContent("transfer_schedule_error_response.json"); + final HyperwalletErrors errors = JsonUtils.fromJsonString(errorResponse, + new TypeReference() { + }); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + HyperwalletListener listener = invocation.getArgument(2); + listener.onFailure(new HyperwalletException(errors)); + return listener; + } + }).when(mHyperwallet).scheduleTransfer(anyString(), anyString(), any(HyperwalletListener.class)); + + Transfer transferRequest = new Transfer.Builder() + .clientTransferID(UUID.randomUUID().toString()) + .createdOn(new Date()) + .destinationAmount("20.00") + .destinationCurrency("USD") + .destinationToken("trm-token") + .sourceToken("usr-token") + .token("trf-token") + .notes("this is the notes") + .build(); + + // test + mTransferRepository.scheduleTransfer(transferRequest, mScheduleTransferCallback); + + verify(mScheduleTransferCallback, never()).onTransferScheduled(any(StatusTransition.class)); + verify(mScheduleTransferCallback).onError(mErrorsArgumentCaptor.capture()); + + HyperwalletErrors capturedErrors = mErrorsArgumentCaptor.getValue(); + assertThat(capturedErrors, is(notNullValue())); + assertThat(capturedErrors.getErrors(), Matchers.hasSize(1)); + assertThat(capturedErrors.getErrors().get(0).getCode(), is("INVALID_STATUS_TRANSITION")); + assertThat(capturedErrors.getErrors().get(0).getMessage(), is("This status transition is not allowed.")); + } +} diff --git a/transferrepository/src/test/resources/transfer_error_response.json b/transferrepository/src/test/resources/transfer_error_response.json new file mode 100644 index 000000000..729ed4ec4 --- /dev/null +++ b/transferrepository/src/test/resources/transfer_error_response.json @@ -0,0 +1,8 @@ +{ + "errors": [ + { + "message": "The source token you provided doesn’t exist or is not a valid source.", + "code": "INVALID_SOURCE_TOKEN" + } + ] +} \ No newline at end of file diff --git a/transferrepository/src/test/resources/transfer_schedule_error_response.json b/transferrepository/src/test/resources/transfer_schedule_error_response.json new file mode 100644 index 000000000..e52ff4cf4 --- /dev/null +++ b/transferrepository/src/test/resources/transfer_schedule_error_response.json @@ -0,0 +1,8 @@ +{ + "errors": [ + { + "message": "This status transition is not allowed.", + "code": "INVALID_STATUS_TRANSITION" + } + ] +} \ No newline at end of file diff --git a/transferrepository/src/test/resources/transfer_scheduled_success_response.json b/transferrepository/src/test/resources/transfer_scheduled_success_response.json new file mode 100644 index 000000000..d33e03c84 --- /dev/null +++ b/transferrepository/src/test/resources/transfer_scheduled_success_response.json @@ -0,0 +1,16 @@ +{ + "token": "sts-token", + "createdOn": "2019-07-23T15:20:17", + "transition": "SCHEDULED", + "fromStatus": "QUOTED", + "toStatus": "SCHEDULED", + "notes": "Completing the Partial-Balance Transfer", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost/rest/v3/transfers/trf-token/status-transitions/sts-token" + } + ] +} \ No newline at end of file diff --git a/transferrepository/src/test/resources/transfer_success_response.json b/transferrepository/src/test/resources/transfer_success_response.json new file mode 100644 index 000000000..15326a2ed --- /dev/null +++ b/transferrepository/src/test/resources/transfer_success_response.json @@ -0,0 +1,23 @@ +{ + "token": "trf-token", + "status": "QUOTED", + "createdOn": "2019-07-08T08:07:46", + "clientTransferId": "007634427520425", + "sourceToken": "usr-token", + "sourceAmount": "27.20", + "sourceCurrency": "USD", + "destinationToken": "trm-token", + "destinationAmount": "25.20", + "destinationFeeAmount": "2.00", + "destinationCurrency": "USD", + "notes": "Partial Balance", + "memo": "TransferClientId56387", + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost/rest/v3/transfers/trf-token" + } + ] +} \ No newline at end of file diff --git a/transferui/build.gradle b/transferui/build.gradle index c7f37807e..6756c2382 100644 --- a/transferui/build.gradle +++ b/transferui/build.gradle @@ -2,6 +2,7 @@ project.ext { mavenName = 'Hyperwallet Android Transfer UI SDK' fileFilter = ['**/BuildConfig.*', '**/com/hyperwallet/android/ui/transfer/view/*.*', + '**/com/hyperwallet/android/ui/transfer/HyperwalletTransferUi.*', '**/com/hyperwallet/android/ui/transfer/viewmodel/*.*' ] } @@ -13,4 +14,21 @@ apply from: "$rootProject.projectDir/publish.gradle" dependencies { implementation project(":transferrepository") implementation project(":transfermethodrepository") -} \ No newline at end of file + implementation project(":userrepository") + implementation project(":commonui") + implementation "androidx.constraintlayout:constraintlayout:$constraintlayoutVersion" + implementation "androidx.legacy:legacy-support-v4:$legacySupportV4Version" + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion" + + androidTestImplementation "androidx.test:rules:$testRulesVersion" + androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" + androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" + androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockServerVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanaryVersion" + androidTestImplementation "com.squareup.leakcanary:leakcanary-support-fragment:$leakcanaryVersion" + androidTestImplementation project(":testutils") + + testImplementation "org.robolectric:robolectric:$robolectricVersion" + testImplementation "com.squareup.okhttp3:mockwebserver:$mockWebServerVersion" + testImplementation project(':testutils') +} diff --git a/transferui/config/jacoco-settings.gradle b/transferui/config/jacoco-settings.gradle new file mode 100644 index 000000000..e69de29bb diff --git a/transferui/config/lint.xml b/transferui/config/lint.xml index 3c83d4bb5..38d8889fb 100644 --- a/transferui/config/lint.xml +++ b/transferui/config/lint.xml @@ -4,4 +4,12 @@ + + + + + + + + \ No newline at end of file diff --git a/transferui/src/androidTest/AndroidManifest.xml b/transferui/src/androidTest/AndroidManifest.xml new file mode 100644 index 000000000..2ad5ff5b0 --- /dev/null +++ b/transferui/src/androidTest/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/HyperwalletInstrumentedTestApplication.java b/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/HyperwalletInstrumentedTestApplication.java new file mode 100644 index 000000000..d37be0cae --- /dev/null +++ b/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/HyperwalletInstrumentedTestApplication.java @@ -0,0 +1,31 @@ +package com.hyperwallet.android.ui.transfer; + + +import android.app.Application; + +import com.squareup.leakcanary.InstrumentationLeakDetector; +import com.squareup.leakcanary.LeakCanary; + +public class HyperwalletInstrumentedTestApplication extends Application { + + @Override + public void onCreate() { + + super.onCreate(); + if (LeakCanary.isInAnalyzerProcess(this)) { + // This process is dedicated to LeakCanary for heap analysis. + // You should not init your app in this process. + return; + } + installLeakCanary(); + } + + + protected void installLeakCanary() { + + InstrumentationLeakDetector.instrumentationRefWatcher(this) + .buildAndInstall(); + + } + +} \ No newline at end of file diff --git a/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/SelectDestinationTest.java b/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/SelectDestinationTest.java new file mode 100644 index 000000000..8aedde82e --- /dev/null +++ b/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/SelectDestinationTest.java @@ -0,0 +1,214 @@ +package com.hyperwallet.android.ui.transfer; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isSelected; +import static androidx.test.espresso.matcher.ViewMatchers.withHint; +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 org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; + +import static java.net.HttpURLConnection.HTTP_OK; + +import static com.hyperwallet.android.ui.testutils.util.EspressoUtils.atPosition; + +import android.widget.TextView; + +import androidx.test.espresso.IdlingRegistry; +import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.rule.ActivityTestRule; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.testutils.TestAuthenticationProvider; +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.transfer.repository.TransferRepositoryFactory; +import com.hyperwallet.android.ui.transfer.view.CreateTransferActivity; +import com.hyperwallet.android.ui.user.repository.UserRepositoryFactory; + +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; + +@RunWith(AndroidJUnit4.class) +public class SelectDestinationTest { + + @ClassRule + public static HyperwalletExternalResourceManager sResourceManager = new HyperwalletExternalResourceManager(); + @Rule + public HyperwalletMockWebServer mMockWebServer = new HyperwalletMockWebServer(8080); + @Rule + public ActivityTestRule mActivityTestRule = + new ActivityTestRule<>(CreateTransferActivity.class, true, false); + + @Before + public void setup() { + Hyperwallet.getInstance(new TestAuthenticationProvider()); + + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("authentication_token_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); + } + + @After + public void cleanup() { + UserRepositoryFactory.clearInstance(); + TransferRepositoryFactory.clearInstance(); + } + + @Before + public void registerIdlingResource() { + IdlingRegistry.getInstance().register(EspressoIdlingResource.getIdlingResource()); + } + + @After + public void unregisterIdlingResource() { + IdlingRegistry.getInstance().unregister(EspressoIdlingResource.getIdlingResource()); + } + + @Test + public void testSelectDestination_verifyActiveExternalAccountsDisplayed() { + 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("create_transfer_quote_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("transfer_method_list_response.json")).mock(); + + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.add_transfer_destination)).check(matches(not(isDisplayed()))); + onView(withId(R.id.transfer_destination)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_destination_icon)).check(matches(withText(R.string.bank_account_font_icon))); + onView(withId(R.id.transfer_destination_title)).check(matches(withText(R.string.bank_account))); + onView(withId(R.id.transfer_destination_selection)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_destination_description_1)).check(matches(withText("United States"))); + onView(withId(R.id.transfer_destination_description_2)).check(matches(withText("Ending on 7267"))); + + onView(withId(R.id.transfer_destination_title)).perform(click()); + + onView(allOf(instanceOf(TextView.class), + withParent(withId(R.id.transfer_destination_selection_toolbar)))).check( + matches(withText(R.string.transfer_destination))); + + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(0, hasDescendant(withText(R.string.bank_account_font_icon))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(0, hasDescendant(withText(R.string.bank_account))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(0, hasDescendant(withText("United States"))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(0, hasDescendant(withText("Ending on 1332"))))); + + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(1, hasDescendant(withText(R.string.bank_card_font_icon))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(1, hasDescendant(withText(R.string.bank_card))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(1, hasDescendant(withText("United States"))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(1, hasDescendant(withText("Ending on 0006"))))); + + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(2, hasDescendant(withText(R.string.wire_account_font_icon))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(2, hasDescendant(withText(R.string.wire_account))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(2, hasDescendant(withText("United States"))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(2, hasDescendant(withText("Ending on 8337"))))); + + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(3, hasDescendant(withText(R.string.paper_check_font_icon))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(3, hasDescendant(withText(R.string.paper_check))))); + onView(withId(R.id.transfer_destination_list)).check(matches(atPosition(3, hasDescendant(withText("Canada"))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(3, hasDescendant(withText(""))))); + + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(4, hasDescendant(withText(R.string.prepaid_card_font_icon))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(4, hasDescendant(withText(R.string.prepaid_card))))); + onView(withId(R.id.transfer_destination_list)).check(matches(atPosition(4, hasDescendant(withText("Canada"))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(4, hasDescendant(withText("Ending on 3187"))))); + + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(5, hasDescendant(withText(R.string.paypal_account_font_icon))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(5, hasDescendant(withText(R.string.paypal_account))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(5, hasDescendant(withText("United States"))))); + onView(withId(R.id.transfer_destination_list)).check( + matches(atPosition(5, hasDescendant(withText("honey.thigpen@ukbuilder.com"))))); + + onView(withId(R.id.transfer_destination_list)).check(new RecyclerViewCountAssertion(6)); + + } + + @Test + public void testSelectDestination_verifyDestinationNotUpdatedWhenClickingBackButton() { + } + + @Test + public void testSelectDestination_verifyDestinationUpdatedUponAddingNewExternalAccount() { + } + + @Test + public void testSelectDestination_verifyDestinationUpdatedUponSelection() { + 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("create_transfer_quote_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("transfer_method_list_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("create_transfer_paypal_quote_response.json")).mock(); + + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.add_transfer_destination)).check(matches(not(isDisplayed()))); + onView(withId(R.id.transfer_destination)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_destination_icon)).check(matches(withText(R.string.bank_account_font_icon))); + onView(withId(R.id.transfer_destination_title)).check(matches(withText(R.string.bank_account))); + onView(withId(R.id.transfer_destination_selection)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_destination_description_1)).check(matches(withText("United States"))); + onView(withId(R.id.transfer_destination_description_2)).check(matches(withText("Ending on 7267"))); + + onView(withId(R.id.transfer_destination_title)).perform(click()); + + onView(withId(R.id.transfer_destination_list)).perform(RecyclerViewActions.actionOnItemAtPosition(5, click())); + onView(withId(R.id.transfer_destination)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_destination_icon)).check(matches(withText(R.string.paypal_account_font_icon))); + onView(withId(R.id.transfer_destination_title)).check(matches(withText(R.string.paypal_account))); + onView(withId(R.id.transfer_destination_selection)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_destination_description_1)).check(matches(withText("United States"))); + onView(withId(R.id.transfer_destination_description_2)).check(matches(withText("honey.thigpen@ukbuilder.com"))); + + onView(withId(R.id.transfer_amount)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_amount)).check(matches(withHint("Amount"))); + onView(withId(R.id.transfer_amount_currency)).check(matches(withText("USD"))); + + //Check that the toggle is disabled by default + onView(withId(R.id.switchButton)).check(matches(isDisplayed())); + onView(withId(R.id.switchButton)).check(matches(not(isSelected()))); + onView(withId(R.id.transfer_summary)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_summary)).check(matches(withText("Available for Transfer: 100.00 USD"))); + } + +} diff --git a/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/TransferUserFundsTest.java b/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/TransferUserFundsTest.java new file mode 100644 index 000000000..209fbc443 --- /dev/null +++ b/transferui/src/androidTest/java/com/hyperwallet/android/ui/transfer/TransferUserFundsTest.java @@ -0,0 +1,167 @@ +package com.hyperwallet.android.ui.transfer; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; +import static androidx.test.espresso.matcher.ViewMatchers.isSelected; +import static androidx.test.espresso.matcher.ViewMatchers.withHint; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; + +import static org.hamcrest.Matchers.not; + +import static java.net.HttpURLConnection.HTTP_NO_CONTENT; +import static java.net.HttpURLConnection.HTTP_OK; + +import androidx.test.espresso.IdlingRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.rule.ActivityTestRule; + +import com.hyperwallet.android.Hyperwallet; +import com.hyperwallet.android.ui.common.repository.EspressoIdlingResource; +import com.hyperwallet.android.ui.testutils.TestAuthenticationProvider; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletExternalResourceManager; +import com.hyperwallet.android.ui.testutils.rule.HyperwalletMockWebServer; +import com.hyperwallet.android.ui.transfer.repository.TransferRepositoryFactory; +import com.hyperwallet.android.ui.transfer.view.CreateTransferActivity; +import com.hyperwallet.android.ui.user.repository.UserRepositoryFactory; + +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; + +@RunWith(AndroidJUnit4.class) +public class TransferUserFundsTest { + + @ClassRule + public static HyperwalletExternalResourceManager sResourceManager = new HyperwalletExternalResourceManager(); + @Rule + public HyperwalletMockWebServer mMockWebServer = new HyperwalletMockWebServer(8080); + @Rule + public ActivityTestRule mActivityTestRule = + new ActivityTestRule<>(CreateTransferActivity.class, true, false); + + @Before + public void setup() { + Hyperwallet.getInstance(new TestAuthenticationProvider()); + + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("authentication_token_response.json")).mock(); + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_OK).withBody(sResourceManager + .getResourceContent("user_response.json")).mock(); + } + + @After + public void cleanup() { + UserRepositoryFactory.clearInstance(); + TransferRepositoryFactory.clearInstance(); + } + + @Before + public void registerIdlingResource() { + IdlingRegistry.getInstance().register(EspressoIdlingResource.getIdlingResource()); + } + + @After + public void unregisterIdlingResource() { + IdlingRegistry.getInstance().unregister(EspressoIdlingResource.getIdlingResource()); + } + + @Test + public void testTransferFunds_verifyTransferButtonDisabledWhenAmountNotSet() { + 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("create_transfer_quote_response.json")).mock(); + + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.add_transfer_destination)).check(matches(not(isDisplayed()))); + onView(withId(R.id.transfer_destination)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_destination_icon)).check(matches(withText(R.string.bank_account_font_icon))); + onView(withId(R.id.transfer_destination_title)).check(matches(withText(R.string.bank_account))); + onView(withId(R.id.transfer_destination_selection)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_destination_description_1)).check(matches(withText("United States"))); + onView(withId(R.id.transfer_destination_description_2)).check(matches(withText("Ending on 7267"))); + + onView(withId(R.id.transfer_amount)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_amount)).check(matches(withHint("Amount"))); + onView(withId(R.id.transfer_amount_currency)).check(matches(withText("USD"))); + onView(withId(R.id.transfer_all_funds_label)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_all_funds_label)).check(matches(withText(R.string.transfer_all_funds_label))); + + //Check that the toggle is disabled by default + onView(withId(R.id.switchButton)).check(matches(isDisplayed())); + onView(withId(R.id.switchButton)).check(matches(not(isSelected()))); + onView(withId(R.id.transfer_summary)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_summary)).check(matches(withText("Available for Transfer: 98.00 USD"))); + + onView(withId(R.id.transfer_notes)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_notes)).check(matches(withHint("Description"))); + onView(withText(R.string.transfer_notes_additional_info_label)).check(matches(isDisplayed())); + + onView(withId(R.id.transfer_action_button)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_action_button)).check(matches(not(isEnabled()))); + } + + @Test + public void testTransferFunds_verifyAddDestinationDisplayedWhenUserHasNoExternalAccounts() { + mMockWebServer.mockResponse().withHttpResponseCode(HTTP_NO_CONTENT).withBody("").mock(); + + mActivityTestRule.launchActivity(null); + + onView(withId(R.id.add_transfer_destination)).check(matches(isDisplayed())); + onView(withId(R.id.add_transfer_destination_icon)).check(matches(withText(R.string.add_text))); + onView(withId(R.id.add_transfer_destination_title)).check(matches(withText(R.string.add_transfer_label))); + onView(withId(R.id.add_transfer_destination_description_1)).check( + matches(withText(R.string.add_transfer_description_1))); + onView(withId(R.id.add_transfer_destination_description_2)).check( + matches(withText(R.string.add_transfer_description_2))); + + onView(withId(R.id.transfer_summary)).check(matches(not(isDisplayed()))); + onView(withId(R.id.transfer_action_button)).check(matches(isDisplayed())); + onView(withId(R.id.transfer_action_button)).check(matches(not(isEnabled()))); + } + + @Test + public void testTransferFunds_createTransferWithFX() { + + } + + @Test + public void testTransferFunds_createTransferWithNoFX() { + } + + @Test + public void testTransferFunds_createTransferWithNotes() { + } + + @Test + public void testTransferFunds_createTransferWithAllFunds() { + } + + @Test + public void testTransferFunds_createTransferLimitError() { + } + + @Test + public void testTransferFunds_createTransferInsufficientFundsError() { + } + + @Test + public void testTransferFunds_createTransferMinimumAmountError() { + } + + @Test + public void testTransferFunds_createTransferInvalidSourceError() { + } + + @Test + public void testTransferFunds_createTransferConnectionError() { + } + +} diff --git a/transferui/src/main/AndroidManifest.xml b/transferui/src/main/AndroidManifest.xml index 8b6760c59..62690572a 100644 --- a/transferui/src/main/AndroidManifest.xml +++ b/transferui/src/main/AndroidManifest.xml @@ -1,2 +1,22 @@ - + + + + + + + + + + + + \ No newline at end of file diff --git a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferUi.java b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferUi.java index 0c76f133e..9cc4534bb 100644 --- a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferUi.java +++ b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/HyperwalletTransferUi.java @@ -17,10 +17,14 @@ package com.hyperwallet.android.ui.transfer; +import android.content.Context; +import android.content.Intent; + import androidx.annotation.NonNull; import com.hyperwallet.android.Hyperwallet; import com.hyperwallet.android.HyperwalletAuthenticationTokenProvider; +import com.hyperwallet.android.ui.transfer.view.CreateTransferActivity; /* Class responsible for initializing the Hyperwallet Transfer UI SDK. It contains methods to interact with the * activities and fragments used to interact with the Hyperwallet platform @@ -47,5 +51,14 @@ public static synchronized HyperwalletTransferUi getInstance( return sInstance; } - //todo: Add outer methods here + public Intent getIntentCreateTransfer(@NonNull final Context context) { + Intent intent = new Intent(context, CreateTransferActivity.class); + return intent; + } + + public Intent getIntentCreateTransfer(@NonNull final Context context, @NonNull final String sourceToken) { + Intent intent = new Intent(context, CreateTransferActivity.class); + intent.putExtra(CreateTransferActivity.EXTRA_TRANSFER_SOURCE_TOKEN, sourceToken); + return intent; + } } diff --git a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/CreateTransferActivity.java b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/CreateTransferActivity.java new file mode 100644 index 000000000..e82b0fb8e --- /dev/null +++ b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/CreateTransferActivity.java @@ -0,0 +1,140 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.transfer.view; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; + +import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.ui.common.repository.Event; +import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.ui.transfer.R; +import com.hyperwallet.android.ui.transfer.repository.TransferRepositoryFactory; +import com.hyperwallet.android.ui.transfer.viewmodel.CreateTransferViewModel; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; +import com.hyperwallet.android.ui.user.repository.UserRepositoryFactory; + +import java.util.List; + +/** + * Create Transfer Activity + */ +public class CreateTransferActivity extends AppCompatActivity { + + public static final String EXTRA_TRANSFER_SOURCE_TOKEN = "TRANSFER_SOURCE_TOKEN"; + + private CreateTransferViewModel mCreateTransferViewModel; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create_transfer); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + getSupportActionBar().setTitle(R.string.title_activity_create_transfer); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + // initialize view model factory based from intent parameters + String sourceToken = getIntent().getStringExtra(EXTRA_TRANSFER_SOURCE_TOKEN); + + final CreateTransferViewModel.CreateTransferViewModelFactory factory; + if (TextUtils.isEmpty(sourceToken)) { + factory = new CreateTransferViewModel.CreateTransferViewModelFactory( + TransferRepositoryFactory.getInstance().getTransferRepository(), + TransferMethodRepositoryFactory.getInstance().getTransferMethodRepository(), + UserRepositoryFactory.getInstance().getUserRepository()); + } else { + factory = new CreateTransferViewModel.CreateTransferViewModelFactory(sourceToken, + TransferRepositoryFactory.getInstance().getTransferRepository(), + TransferMethodRepositoryFactory.getInstance().getTransferMethodRepository(), + UserRepositoryFactory.getInstance().getUserRepository()); + } + + mCreateTransferViewModel = ViewModelProviders.of(this, factory).get(CreateTransferViewModel.class); + mCreateTransferViewModel.getLoadErrorEvent().observe(this, new Observer>() { + @Override + public void onChanged(Event event) { + if (event != null && !event.isContentConsumed()) { + showErrorOnLoadCreateTransfer(event.getContent().getErrors()); + } + } + }); + + //TODO temporarily display dialog on all quote transfer error + mCreateTransferViewModel.getCreateTransferErrors().observe(this, new Observer>() { + @Override + public void onChanged(Event event) { + if (event != null && !event.isContentConsumed()) { + showErrorOnLoadCreateTransfer(event.getContent().getErrors()); + } + } + }); + + if (savedInstanceState == null) { + initFragment(CreateTransferFragment.newInstance()); + } + } + + @Override + protected void onDestroy() { + TransferRepositoryFactory.clearInstance(); + TransferMethodRepositoryFactory.clearInstance(); + UserRepositoryFactory.clearInstance(); + super.onDestroy(); + } + + private void initFragment(@NonNull final Fragment fragment) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.add(R.id.create_transfer_fragment, fragment); + fragmentTransaction.commit(); + } + + + private void showErrorOnLoadCreateTransfer(@NonNull final List errors) { + FragmentManager fragmentManager = getSupportFragmentManager(); + DefaultErrorDialogFragment fragment = (DefaultErrorDialogFragment) + fragmentManager.findFragmentByTag(DefaultErrorDialogFragment.TAG); + + if (fragment == null) { + fragment = DefaultErrorDialogFragment.newInstance(errors); + } + + if (!fragment.isAdded()) { + fragment.show(fragmentManager); + } + } +} diff --git a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/CreateTransferFragment.java b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/CreateTransferFragment.java new file mode 100644 index 000000000..280a8933c --- /dev/null +++ b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/CreateTransferFragment.java @@ -0,0 +1,395 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.transfer.view; + +import static android.app.Activity.RESULT_OK; + +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TOKEN; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_CURRENCY; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TYPE; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getStringFontIcon; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getStringResourceByName; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getTransferMethodDetail; + +import android.content.Intent; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.Switch; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; + +import com.google.android.material.snackbar.Snackbar; +import com.hyperwallet.android.model.transfer.Transfer; +import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.ui.common.view.OneClickListener; +import com.hyperwallet.android.ui.transfer.R; +import com.hyperwallet.android.ui.transfer.viewmodel.CreateTransferViewModel; + +import java.util.Locale; + + +/** + * Create Transfer Fragment + */ +public class CreateTransferFragment extends Fragment { + + public static final short SELECT_TRANSFER_DESTINATION_RESULT_CODE = 101; + + private static final String EMPTY_STRING = ""; + private View mProgressBar; + private CreateTransferViewModel mCreateTransferViewModel; + private EditText mTransferAmount; + private TextView mTransferCurrency; + private TextView mTransferAllFundsSummary; + private EditText mTransferNotes; + private Button mTransferNextButton; + private View mTransferNextButtonProgress; + private View mTransferDestination; + private View mAddTransferDestination; + private Switch mTransferAllSwitch; + + /** + * Please don't use this constructor this is reserved for Android Core Framework + * + * @see #newInstance() + */ + public CreateTransferFragment() { + } + + static CreateTransferFragment newInstance() { + return new CreateTransferFragment(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCreateTransferViewModel = ViewModelProviders.of(requireActivity()).get(CreateTransferViewModel.class); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_create_transfer, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + mProgressBar = view.findViewById(R.id.progress_bar); + mTransferAllFundsSummary = view.findViewById(R.id.transfer_summary); + mTransferNextButtonProgress = view.findViewById(R.id.transfer_action_button_progress_bar); + + mTransferCurrency = view.findViewById(R.id.transfer_amount_currency); + mTransferCurrency.setText(EMPTY_STRING); + + // next button + mTransferNextButton = view.findViewById(R.id.transfer_action_button); + mTransferNextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mCreateTransferViewModel.createTransfer(); + } + }); + disableNextButton(); + + // transfer amount + mTransferAmount = view.findViewById(R.id.transfer_amount); + prepareTransferAmount(); + + // transfer notes; + mTransferNotes = view.findViewById(R.id.transfer_notes); + prepareTransferNotes(); + + // transfer destination + mTransferDestination = view.findViewById(R.id.transfer_destination); + mTransferDestination.setOnClickListener(new OneClickListener() { + @Override + public void onOneClick(View v) { + HyperwalletTransferMethod activeDestination = + mCreateTransferViewModel.getTransferDestination().getValue(); + Intent intent = new Intent(requireContext(), ListTransferDestinationActivity.class); + intent.putExtra(ListTransferDestinationActivity.EXTRA_SELECTED_DESTINATION_TOKEN, + activeDestination.getField(TOKEN)); + startActivityForResult(intent, SELECT_TRANSFER_DESTINATION_RESULT_CODE); + } + }); + + // add transfer destination + mAddTransferDestination = view.findViewById(R.id.add_transfer_destination); + mAddTransferDestination.setOnClickListener(new OneClickListener() { + @Override + public void onOneClick(View v) { + //TODO temporary action for transfer destination clicked; it should open up add transfer method UI + Snackbar.make(mAddTransferDestination, "ADD Transfer clicked", Snackbar.LENGTH_SHORT).show(); + } + }); + + // toggle button + mTransferAllSwitch = view.findViewById(R.id.switchButton); + mTransferAllSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mCreateTransferViewModel.setTransferAllAvailableFunds(isChecked); + } + }); + registerTransferDestinationObserver(); + registerAvailableFundsObserver(); + registerTransferAmountObserver(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK && requestCode == SELECT_TRANSFER_DESTINATION_RESULT_CODE && data != null) { + HyperwalletTransferMethod selectedTransferMethod = data.getParcelableExtra( + ListTransferDestinationActivity.EXTRA_SELECTED_DESTINATION_TOKEN); + mCreateTransferViewModel.setTransferDestination(selectedTransferMethod); + } + } + + private void prepareTransferAmount() { + mTransferAmount.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus) { + mCreateTransferViewModel.setTransferAmount(((EditText) v).getText().toString()); + } + } + }); + mTransferAmount.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (before != count) { + mCreateTransferViewModel.setTransferAmount(s.toString()); + } + + if (TextUtils.isEmpty(mTransferAmount.getText())) { + disableNextButton(); + } else { + enableNextButton(); + } + } + + @Override + public void afterTextChanged(Editable s) { + } + }); + } + + private void prepareTransferNotes() { + mTransferNotes.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus) { + mCreateTransferViewModel.setTransferNotes(((EditText) v).getText().toString()); + } + } + }); + mTransferNotes.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (before != count) { + mCreateTransferViewModel.setTransferNotes(s.toString()); + } + } + + @Override + public void afterTextChanged(Editable s) { + } + }); + } + + private void registerTransferDestinationObserver() { + mCreateTransferViewModel.isLoading().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(final Boolean loading) { + if (loading) { + mProgressBar.setVisibility(View.VISIBLE); + disableInputControls(); + } else { + mProgressBar.setVisibility(View.GONE); + enableInputControls(); + } + } + }); + + mCreateTransferViewModel.getTransferDestination().observe(getViewLifecycleOwner(), + new Observer() { + @Override + public void onChanged(final HyperwalletTransferMethod transferMethod) { + if (transferMethod != null) { + showTransferDestination(transferMethod); + enableInputControls(); + } else { + mAddTransferDestination.setVisibility(View.VISIBLE); + mTransferDestination.setVisibility(View.GONE); + disableInputControls(); + } + } + }); + } + + private void registerAvailableFundsObserver() { + mCreateTransferViewModel.getQuoteAvailableFunds().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(final Transfer transfer) { + if (transfer != null) { + String summary = requireContext().getString(R.string.transfer_summary_label, + transfer.getDestinationAmount(), transfer.getDestinationCurrency()); + mTransferAllFundsSummary.setText(summary); + mTransferAllFundsSummary.setVisibility(View.VISIBLE); + } + } + }); + } + + private void registerTransferAmountObserver() { + mCreateTransferViewModel.isTransferAllAvailableFunds().observe(getViewLifecycleOwner(), + new Observer() { + @Override + public void onChanged(final Boolean transferAll) { + if (transferAll) { + Transfer transfer = mCreateTransferViewModel.getQuoteAvailableFunds().getValue(); + if (transfer != null) { + mTransferCurrency.setTextColor( + getResources().getColor(R.color.colorButtonTextDisabled)); + mTransferAmount.setEnabled(false); + mTransferAmount.setText(transfer.getDestinationAmount()); + } + } else { + mTransferCurrency.setTextColor(getResources().getColor(R.color.colorSecondaryDark)); + mTransferAmount.setEnabled(true); + mTransferAmount.setText(null); + } + } + }); + + mCreateTransferViewModel.getTransferAmount().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(String amount) { + mTransferAmount.setText(amount); + mTransferAmount.setSelection(TextUtils.isEmpty(amount) ? 0 : amount.length()); + } + }); + + mCreateTransferViewModel.getTransferNotes().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(String notes) { + mTransferNotes.setText(notes); + mTransferNotes.setSelection(TextUtils.isEmpty(notes) ? 0 : notes.length()); + } + }); + + mCreateTransferViewModel.isCreateQuoteLoading().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(Boolean loading) { + if (loading) { + mTransferNextButtonProgress.setVisibility(View.VISIBLE); + disableInputControls(); + } else { + mTransferNextButtonProgress.setVisibility(View.GONE); + enableInputControls(); + } + } + }); + + mCreateTransferViewModel.getCreateTransfer().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(Transfer transfer) { + // TODO create intent to call next Transfer confirmation screen with parcelable payload of Transfer + try { + Snackbar.make(mTransferNextButton, transfer.toJsonString(), Snackbar.LENGTH_SHORT).show(); + } catch (Exception e) { + Snackbar.make(mTransferNextButton, "Exception occurred! Transfer conversion", + Snackbar.LENGTH_SHORT).show(); + } + } + }); + } + + private void disableInputControls() { + mTransferCurrency.setTextColor(getResources().getColor(R.color.colorButtonTextDisabled)); + mTransferAmount.setEnabled(false); + mTransferNotes.setEnabled(false); + mTransferAllSwitch.setEnabled(false); + } + + private void enableInputControls() { + mTransferCurrency.setTextColor(getResources().getColor(R.color.colorSecondaryDark)); + mTransferAmount.setEnabled(true); + mTransferNotes.setEnabled(true); + mTransferAllSwitch.setEnabled(true); + } + + private void enableNextButton() { + if (mCreateTransferViewModel.getTransferDestination().getValue() != null + && mCreateTransferViewModel.getQuoteAvailableFunds().getValue() != null) { + mTransferNextButton.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); + mTransferNextButton.setTextColor(getResources().getColor(R.color.regularColorPrimary)); + mTransferNextButton.setEnabled(true); + } + } + + private void disableNextButton() { + mTransferNextButton.setBackgroundColor(getResources().getColor(R.color.colorSecondary)); + mTransferNextButton.setTextColor(getResources().getColor(R.color.colorSecondaryDark)); + mTransferNextButton.setEnabled(false); + } + + private void showTransferDestination(@NonNull final HyperwalletTransferMethod transferMethod) { + TextView transferIcon = getView().findViewById(R.id.transfer_destination_icon); + TextView transferTitle = getView().findViewById(R.id.transfer_destination_title); + TextView transferCountry = getView().findViewById(R.id.transfer_destination_description_1); + TextView transferIdentifier = getView().findViewById(R.id.transfer_destination_description_2); + + String type = transferMethod.getField(TYPE); + String transferMethodIdentification = getTransferMethodDetail(transferIdentifier.getContext(), transferMethod, + type); + Locale locale = new Locale.Builder().setRegion( + transferMethod.getField(TRANSFER_METHOD_COUNTRY)).build(); + + transferIdentifier.setText(transferMethodIdentification); + transferTitle.setText(getStringResourceByName(transferTitle.getContext(), type)); + transferIcon.setText(getStringFontIcon(transferIcon.getContext(), type)); + transferCountry.setText(locale.getDisplayName()); + + mTransferCurrency.setText(transferMethod.getField(TRANSFER_METHOD_CURRENCY)); + mTransferDestination.setVisibility(View.VISIBLE); + } +} diff --git a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/ListTransferDestinationActivity.java b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/ListTransferDestinationActivity.java new file mode 100644 index 000000000..77daeb589 --- /dev/null +++ b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/ListTransferDestinationActivity.java @@ -0,0 +1,133 @@ +/* + * Copyright 2019 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.transfer.view; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; + +import com.hyperwallet.android.model.HyperwalletError; +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.ui.common.repository.Event; +import com.hyperwallet.android.ui.common.view.error.DefaultErrorDialogFragment; +import com.hyperwallet.android.ui.transfer.R; +import com.hyperwallet.android.ui.transfer.viewmodel.ListTransferDestinationViewModel; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepositoryFactory; + +import java.util.List; + +public class ListTransferDestinationActivity extends AppCompatActivity { + + public static final String EXTRA_SELECTED_DESTINATION_TOKEN = "SELECTED_DESTINATION_TOKEN"; + + private ListTransferDestinationViewModel mListTransferDestinationViewModel; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_list_transfer_destination); + + String transferToken = getIntent().getStringExtra(EXTRA_SELECTED_DESTINATION_TOKEN); + if (TextUtils.isEmpty(transferToken)) { + throw new IllegalArgumentException( + "EXTRA_SELECTED_DESTINATION_TOKEN intent data is needed to start this activity"); + } + + mListTransferDestinationViewModel = ViewModelProviders.of(this, + new ListTransferDestinationViewModel.ListTransferDestinationViewModelFactory( + TransferMethodRepositoryFactory.getInstance().getTransferMethodRepository())) + .get(ListTransferDestinationViewModel.class); + registerObservers(); + + if (savedInstanceState == null) { + initFragment(ListTransferDestinationFragment.newInstance(transferToken)); + } + } + + @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(); + } + + private void initFragment(Fragment fragment) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction transaction = fragmentManager.beginTransaction(); + transaction.add(R.id.list_destination_fragment, fragment); + transaction.commit(); + } + + private void registerObservers() { + mListTransferDestinationViewModel.getSelectedTransferDestination().observe(this, + new Observer>() { + @Override + public void onChanged(Event destination) { + Intent intent = new Intent(); + intent.putExtra(EXTRA_SELECTED_DESTINATION_TOKEN, destination.getContent()); + setResult(Activity.RESULT_OK, intent); + finish(); + } + }); + + mListTransferDestinationViewModel.getTransferDestinationError().observe(this, + new Observer>() { + @Override + public void onChanged(Event errorsEvent) { + if (!errorsEvent.isContentConsumed()) { + showError(errorsEvent.getContent().getErrors()); + } + } + }); + } + + private void showError(@NonNull List errors) { + FragmentManager fragmentManager = getSupportFragmentManager(); + DefaultErrorDialogFragment fragment = (DefaultErrorDialogFragment) + fragmentManager.findFragmentByTag(DefaultErrorDialogFragment.TAG); + + if (fragment == null) { + fragment = DefaultErrorDialogFragment.newInstance(errors); + } + + if (!fragment.isAdded()) { + fragment.show(fragmentManager); + } + } +} \ No newline at end of file diff --git a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/ListTransferDestinationFragment.java b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/ListTransferDestinationFragment.java new file mode 100644 index 000000000..585d5131d --- /dev/null +++ b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/view/ListTransferDestinationFragment.java @@ -0,0 +1,280 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.transfer.view; + +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TOKEN; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TYPE; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getStringFontIcon; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getStringResourceByName; +import static com.hyperwallet.android.ui.common.view.TransferMethodUtils.getTransferMethodDetail; + +import android.app.Activity; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.ImageView; +import android.widget.TextView; + +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.DialogFragment; +import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.ui.transfer.R; +import com.hyperwallet.android.ui.transfer.viewmodel.ListTransferDestinationViewModel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +public class ListTransferDestinationFragment extends DialogFragment { + + public static final String TAG = "HW:" + ListTransferDestinationFragment.class.getSimpleName(); + public static final String ARGUMENT_SELECTED_TRANSFER_TOKEN = "SELECTED_TRANSFER_TOKEN"; + + private ListTransferDestinationViewModel mListTransferDestinationViewModel; + private RecyclerView mRecyclerView; + private ListTransferDestinationAdapter mListTransferDestinationAdapter; + private View mProgressBar; + private String mActiveTransferToken; + + /** + * Please don't use this constructor this is reserved for Android Core Framework + * + * @see #newInstance(String) + */ + public ListTransferDestinationFragment() { + } + + static ListTransferDestinationFragment newInstance(@NonNull final String activeTransferToken) { + Bundle bundle = new Bundle(); + bundle.putString(ARGUMENT_SELECTED_TRANSFER_TOKEN, activeTransferToken); + ListTransferDestinationFragment fragment = new ListTransferDestinationFragment(); + fragment.mActiveTransferToken = activeTransferToken; + fragment.setArguments(bundle); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mListTransferDestinationViewModel = ViewModelProviders.of(requireActivity()).get( + ListTransferDestinationViewModel.class); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.dialog_fragment_list_transfer_destination, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + Toolbar toolbar = view.findViewById(R.id.transfer_destination_selection_toolbar); + toolbar.setTitle(R.string.transfer_destination); + toolbar.setNavigationIcon(R.drawable.ic_close_14dp); + + ((AppCompatActivity) requireActivity()).setSupportActionBar(toolbar); + ((AppCompatActivity) requireActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true); + ((AppCompatActivity) requireActivity()).getSupportActionBar().setDisplayShowHomeEnabled(true); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + hideSoftKey(v); + onClose(); + getFragmentManager().popBackStack(TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); + dismiss(); + requireActivity().finish(); + } + }); + + onView(); + mProgressBar = view.findViewById(R.id.progress_bar); + mRecyclerView = view.findViewById(R.id.transfer_destination_list); + mRecyclerView.setHasFixedSize(true); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + + registerObservers(); + } + + @Override + public void onViewStateRestored(@Nullable Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + + mActiveTransferToken = getArguments().getString(ARGUMENT_SELECTED_TRANSFER_TOKEN); + mListTransferDestinationAdapter = new ListTransferDestinationAdapter(mActiveTransferToken, + mListTransferDestinationViewModel); + mRecyclerView.setAdapter(mListTransferDestinationAdapter); + } + + private void registerObservers() { + mListTransferDestinationViewModel.getTransferDestinationList().observe(getViewLifecycleOwner(), + new Observer>() { + @Override + public void onChanged(List transferMethods) { + if (mListTransferDestinationAdapter != null) { + mListTransferDestinationAdapter.replaceData(transferMethods); + } + } + }); + + mListTransferDestinationViewModel.isLoading().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(Boolean loading) { + if (loading) { + mProgressBar.setVisibility(View.VISIBLE); + } else { + mProgressBar.setVisibility(View.GONE); + } + } + }); + } + + private void hideSoftKey(@NonNull View focusedView) { + InputMethodManager inputMethodManager = (InputMethodManager) focusedView.getContext().getSystemService( + Activity.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(focusedView.getWindowToken(), 0); + } + + private void onClose() { + requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + requireActivity().getWindow().setStatusBarColor(ContextCompat.getColor(getContext(), R.color.colorPrimaryDark)); + requireActivity().getWindow().getDecorView().setSystemUiVisibility(0); + } + + private void onView() { + requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + getActivity().getWindow().setStatusBarColor( + ContextCompat.getColor(getContext(), R.color.regularColorPrimary)); + getActivity().getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } + } + + private class ListTransferDestinationAdapter extends RecyclerView.Adapter { + + private final List mTransferDestinations = new ArrayList<>(); + private final ListTransferDestinationViewModel mViewModel; + private final String mSelectedDestination; + + ListTransferDestinationAdapter(@NonNull final String selectedDestination, + @NonNull final ListTransferDestinationViewModel viewModel) { + mSelectedDestination = selectedDestination; + mViewModel = viewModel; + } + + @NonNull + @Override + public TransferDestinationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + Context context = parent.getContext(); + LayoutInflater layoutInflater = LayoutInflater.from(context); + View itemCurrencyView = layoutInflater.inflate(R.layout.item_transfer_destination, parent, false); + + return new TransferDestinationViewHolder(itemCurrencyView, mViewModel); + } + + @Override + public void onBindViewHolder(@NonNull TransferDestinationViewHolder holder, int position) { + HyperwalletTransferMethod destination = mTransferDestinations.get(position); + holder.bind(destination, Objects.equals(destination.getField(TOKEN), mSelectedDestination)); + } + + @Override + public int getItemCount() { + return mTransferDestinations.size(); + } + + @Override + public void onViewRecycled(@NonNull TransferDestinationViewHolder holder) { + holder.recycle(); + } + + void replaceData(@NonNull final List destinations) { + mTransferDestinations.clear(); + mTransferDestinations.addAll(destinations); + notifyDataSetChanged(); + } + } + + private class TransferDestinationViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + private final TextView mTitle; + private final TextView mIcon; + private final TextView mTransferDestinationCountry; + private final TextView mTransferDestinationIdentification; + private final ImageView mSelectedIcon; + private final ListTransferDestinationViewModel mViewModel; + private HyperwalletTransferMethod mTransferMethod; + + TransferDestinationViewHolder(@NonNull final View itemView, + @NonNull final ListTransferDestinationViewModel viewModel) { + super(itemView); + itemView.setOnClickListener(this); + + mIcon = itemView.findViewById(R.id.icon); + mTitle = itemView.findViewById(R.id.title); + mTransferDestinationCountry = itemView.findViewById(R.id.description_1); + mTransferDestinationIdentification = itemView.findViewById(R.id.description_2); + mSelectedIcon = itemView.findViewById(R.id.item_selected_image); + mViewModel = viewModel; + } + + @Override + public void onClick(View v) { + mViewModel.selectedTransferDestination(mTransferMethod); + } + + void bind(@NonNull final HyperwalletTransferMethod destination, final boolean selected) { + mTransferMethod = destination; + String type = destination.getField(TYPE); + Locale locale = new Locale.Builder().setRegion(destination.getField(TRANSFER_METHOD_COUNTRY)).build(); + String transferId = getTransferMethodDetail(mTitle.getContext(), destination, type); + + mTitle.setText(getStringResourceByName(mTitle.getContext(), type)); + mIcon.setText(getStringFontIcon(mIcon.getContext(), type)); + mTransferDestinationCountry.setText(locale.getDisplayName()); + mTransferDestinationIdentification.setText(transferId); + + if (selected) { + mSelectedIcon.setVisibility(View.VISIBLE); + } else { + mSelectedIcon.setVisibility(View.GONE); + } + } + + void recycle() { + itemView.setOnClickListener(null); + } + } +} diff --git a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/viewmodel/CreateTransferViewModel.java b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/viewmodel/CreateTransferViewModel.java new file mode 100644 index 000000000..1ee4e85e4 --- /dev/null +++ b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/viewmodel/CreateTransferViewModel.java @@ -0,0 +1,344 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.transfer.viewmodel; + +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TOKEN; +import static com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_CURRENCY; + +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.transfer.Transfer; +import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.model.user.HyperwalletUser; +import com.hyperwallet.android.ui.common.repository.Event; +import com.hyperwallet.android.ui.transfer.repository.TransferRepository; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepository; +import com.hyperwallet.android.ui.user.repository.UserRepository; + +import java.util.UUID; + +/** + * Create Transfer View Model + */ +public class CreateTransferViewModel extends ViewModel { + + private static final String CLIENT_IDENTIFICATION_PREFIX = "HW-ANDROID-"; + + private final TransferRepository mTransferRepository; + private final TransferMethodRepository mTransferMethodRepository; + private final UserRepository mUserRepository; + + private final MutableLiveData mTransferDestination = new MutableLiveData<>(); + private final MutableLiveData mTransferAvailableFunds = new MutableLiveData<>(); + private final MutableLiveData mIsLoading = new MutableLiveData<>(); + private final MutableLiveData mIsCreateQuoteLoading = new MutableLiveData<>(); + private final MutableLiveData mQuoteAvailableFunds = new MutableLiveData<>(); + private final MutableLiveData mCreateTransfer = new MutableLiveData<>(); + private final MutableLiveData mTransferAmount = new MutableLiveData<>(); + private final MutableLiveData mTransferNotes = new MutableLiveData<>(); + + // initialisation/loading error + private Observer> mLoadErrorEventObserver; + private final MutableLiveData> mLoadErrorEvent = new MutableLiveData<>(); + private final MutableLiveData> mLoadErrors = new MutableLiveData<>(); + + // create quote error + private Observer> mCreateTransferEventObserver; + private final MutableLiveData> mCreateTransferErrorEvent = new MutableLiveData<>(); + private final MutableLiveData> mCreateTransferErrors = new MutableLiveData<>(); + + /** + * Initialize Create Transfer View Model with designated transfer source token + * + * @param sourceToken Source token that represents either from User, Bank or PrepaidCard tokens + * @param transferRepository Transfer repository for making transfer calls to Hyperwallet + * @param transferMethodRepository Transfer Method repository for making transfer method calls to Hyperwallet + * @param userRepository User repository for making user calls to Hyperwallet + */ + CreateTransferViewModel(@NonNull final String sourceToken, + @NonNull final TransferRepository transferRepository, + @NonNull final TransferMethodRepository transferMethodRepository, + @NonNull final UserRepository userRepository) { + + mTransferRepository = transferRepository; + mTransferMethodRepository = transferMethodRepository; + mUserRepository = userRepository; + + // initialize + mTransferAvailableFunds.setValue(Boolean.FALSE); + mIsLoading.postValue(Boolean.TRUE); + mIsCreateQuoteLoading.setValue(Boolean.FALSE); + createLoadErrorObserver(); + loadTransferDestination(sourceToken); + } + + /** + * Initialize Create Transfer View Model with designated transfer source token + * + * @param transferRepository Transfer repository for making transfer calls to Hyperwallet + * @param transferMethodRepository Transfer Method repository for making transfer method calls to Hyperwallet + * @param userRepository User repository for making user calls to Hyperwallet + */ + CreateTransferViewModel(@NonNull final TransferRepository transferRepository, + @NonNull final TransferMethodRepository transferMethodRepository, + @NonNull final UserRepository userRepository) { + + mTransferRepository = transferRepository; + mTransferMethodRepository = transferMethodRepository; + mUserRepository = userRepository; + + // initialize + mTransferAvailableFunds.setValue(Boolean.FALSE); + mIsLoading.postValue(Boolean.TRUE); + mIsCreateQuoteLoading.setValue(Boolean.FALSE); + createLoadErrorObserver(); + loadTransferSource(); + createTransferErrorObserver(); + } + + public LiveData isTransferAllAvailableFunds() { + return mTransferAvailableFunds; + } + + public void setTransferAllAvailableFunds(@NonNull final Boolean transferAll) { + mTransferAvailableFunds.postValue(transferAll); + } + + public void setTransferAmount(@NonNull final String amount) { + mTransferAmount.postValue(amount); + } + + public LiveData getTransferAmount() { + return mTransferAmount; + } + + public void setTransferNotes(@Nullable final String notes) { + mTransferNotes.postValue(notes); + } + + public LiveData getTransferNotes() { + return mTransferNotes; + } + + public LiveData getTransferDestination() { + return mTransferDestination; + } + + public void setTransferDestination(@NonNull final HyperwalletTransferMethod transferDestination) { + mTransferDestination.postValue(transferDestination); + if (mQuoteAvailableFunds.getValue() != null) { + mIsLoading.postValue(Boolean.TRUE); + quoteAvailableTransferFunds(mQuoteAvailableFunds.getValue().getSourceToken(), transferDestination); + } + } + + public LiveData isLoading() { + return mIsLoading; + } + + public LiveData isCreateQuoteLoading() { + return mIsCreateQuoteLoading; + } + + public LiveData getQuoteAvailableFunds() { + return mQuoteAvailableFunds; + } + + public LiveData> getLoadErrorEvent() { + return mLoadErrorEvent; + } + + public LiveData getCreateTransfer() { + return mCreateTransfer; + } + + public LiveData> getCreateTransferErrors() { + return mCreateTransferErrorEvent; + } + + public void createTransfer() { + mIsCreateQuoteLoading.postValue(Boolean.TRUE); + Transfer transfer = mTransferAvailableFunds.getValue() ? + new Transfer.Builder() + .clientTransferID(CLIENT_IDENTIFICATION_PREFIX + UUID.randomUUID().toString()) + .sourceToken(mQuoteAvailableFunds.getValue().getSourceToken()) + .destinationToken(mTransferDestination.getValue().getField(TOKEN)) + .destinationCurrency(mTransferDestination.getValue().getField(TRANSFER_METHOD_CURRENCY)) + .notes(mTransferNotes.getValue()) + .build() : + new Transfer.Builder() + .clientTransferID(CLIENT_IDENTIFICATION_PREFIX + UUID.randomUUID().toString()) + .sourceToken(mQuoteAvailableFunds.getValue().getSourceToken()) + .destinationToken(mTransferDestination.getValue().getField(TOKEN)) + .destinationCurrency(mTransferDestination.getValue().getField(TRANSFER_METHOD_CURRENCY)) + .notes(mTransferNotes.getValue()) + .destinationAmount(mTransferAmount.getValue()) + .build(); + + mTransferRepository.createTransfer(transfer, new TransferRepository.CreateTransferCallback() { + @Override + public void onTransferCreated(@Nullable Transfer transfer) { + mCreateTransfer.postValue(transfer); + mIsCreateQuoteLoading.postValue(Boolean.FALSE); + } + + @Override + public void onError(@NonNull HyperwalletErrors errors) { + mCreateTransferErrors.postValue(new Event<>(errors)); + mIsCreateQuoteLoading.postValue(Boolean.FALSE); + } + }); + } + + @Override + protected void onCleared() { + super.onCleared(); + mLoadErrors.removeObserver(mLoadErrorEventObserver); + mCreateTransferErrors.removeObserver(mCreateTransferEventObserver); + } + + private void createLoadErrorObserver() { + mLoadErrorEventObserver = new Observer>() { + @Override + public void onChanged(Event event) { + mLoadErrorEvent.postValue(event); + } + }; + mLoadErrors.observeForever(mLoadErrorEventObserver); + } + + private void createTransferErrorObserver() { + mCreateTransferEventObserver = new Observer>() { + @Override + public void onChanged(Event event) { + mCreateTransferErrorEvent.postValue(event); + } + }; + mCreateTransferErrors.observeForever(mCreateTransferEventObserver); + } + + private void loadTransferSource() { + mUserRepository.loadUser(new UserRepository.LoadUserCallback() { + @Override + public void onUserLoaded(@NonNull HyperwalletUser user) { + loadTransferDestination(user.getToken()); + } + + @Override + public void onError(@NonNull HyperwalletErrors errors) { + mIsLoading.postValue(Boolean.FALSE); + mLoadErrors.postValue(new Event<>(errors)); + } + }); + } + + private void loadTransferDestination(@NonNull final String sourceToken) { + mTransferMethodRepository.loadLatestTransferMethod(new TransferMethodRepository.LoadTransferMethodCallback() { + @Override + public void onTransferMethodLoaded(@Nullable HyperwalletTransferMethod transferMethod) { + mTransferDestination.postValue(transferMethod); + if (transferMethod == null) { // dismiss quote + mIsLoading.postValue(Boolean.FALSE); + } else { + quoteAvailableTransferFunds(sourceToken, transferMethod); + } + } + + @Override + public void onError(HyperwalletErrors errors) { + mIsLoading.postValue(Boolean.FALSE); + mLoadErrors.postValue(new Event<>(errors)); + } + }); + } + + private void quoteAvailableTransferFunds(@NonNull final String sourceToken, + @NonNull final HyperwalletTransferMethod transferMethod) { + + Transfer transfer = new Transfer.Builder() + .clientTransferID(CLIENT_IDENTIFICATION_PREFIX + UUID.randomUUID().toString()) + .sourceToken(sourceToken) + .destinationToken(transferMethod.getField(TOKEN)) + .destinationCurrency(transferMethod.getField(TRANSFER_METHOD_CURRENCY)) + .build(); + + mTransferRepository.createTransfer(transfer, new TransferRepository.CreateTransferCallback() { + @Override + public void onTransferCreated(@Nullable Transfer transfer) { + mIsLoading.postValue(Boolean.FALSE); + mQuoteAvailableFunds.postValue(transfer); + } + + @Override + public void onError(@NonNull HyperwalletErrors errors) { + mIsLoading.postValue(Boolean.FALSE); + mLoadErrors.postValue(new Event<>(errors)); + } + }); + } + + public static class CreateTransferViewModelFactory implements ViewModelProvider.Factory { + + private final TransferRepository transferRepository; + private final TransferMethodRepository transferMethodRepository; + private final UserRepository userRepository; + private final String sourceToken; + + public CreateTransferViewModelFactory(@NonNull final String sourceToken, + @NonNull final TransferRepository transferRepository, + @NonNull final TransferMethodRepository transferMethodRepository, + @NonNull final UserRepository userRepository) { + this.sourceToken = sourceToken; + this.transferMethodRepository = transferMethodRepository; + this.transferRepository = transferRepository; + this.userRepository = userRepository; + } + + public CreateTransferViewModelFactory(@NonNull final TransferRepository transferRepository, + @NonNull final TransferMethodRepository transferMethodRepository, + @NonNull final UserRepository userRepository) { + this.sourceToken = null; + this.transferMethodRepository = transferMethodRepository; + this.transferRepository = transferRepository; + this.userRepository = userRepository; + } + + @NonNull + @Override + public T create(@NonNull Class modelClass) { + if (modelClass.isAssignableFrom(CreateTransferViewModel.class)) { + if (TextUtils.isEmpty(sourceToken)) { + return (T) new CreateTransferViewModel(transferRepository, transferMethodRepository, + userRepository); + } + return (T) new CreateTransferViewModel(sourceToken, transferRepository, transferMethodRepository, + userRepository); + } + + throw new IllegalArgumentException("Expecting ViewModel class: " + CreateTransferViewModel.class.getName()); + } + } +} diff --git a/transferui/src/main/java/com/hyperwallet/android/ui/transfer/viewmodel/ListTransferDestinationViewModel.java b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/viewmodel/ListTransferDestinationViewModel.java new file mode 100644 index 000000000..a52cd565a --- /dev/null +++ b/transferui/src/main/java/com/hyperwallet/android/ui/transfer/viewmodel/ListTransferDestinationViewModel.java @@ -0,0 +1,109 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Hyperwallet Systems Inc. + * + * 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 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.transfer.viewmodel; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; + +import com.hyperwallet.android.model.HyperwalletErrors; +import com.hyperwallet.android.model.transfermethod.HyperwalletTransferMethod; +import com.hyperwallet.android.ui.common.repository.Event; +import com.hyperwallet.android.ui.transfermethod.repository.TransferMethodRepository; + +import java.util.ArrayList; +import java.util.List; + +/** + * List Transfer Destination ViewModel + */ +public class ListTransferDestinationViewModel extends ViewModel { + + private final MutableLiveData> mTransferDestinationList = new MutableLiveData<>(); + private final MutableLiveData mIsLoading = new MutableLiveData<>(); + private final MutableLiveData> mSelectedTransferDestination = + new MutableLiveData<>(); + private final MutableLiveData> mTransferDestinationError = new MutableLiveData<>(); + private final TransferMethodRepository mTransferMethodRepository; + + ListTransferDestinationViewModel(@NonNull final TransferMethodRepository repository) { + mTransferMethodRepository = repository; + loadTransferDestinationList(); + } + + public void selectedTransferDestination(@NonNull final HyperwalletTransferMethod transferMethod) { + mSelectedTransferDestination.postValue(new Event<>(transferMethod)); + } + + public LiveData> getTransferDestinationList() { + return mTransferDestinationList; + } + + public LiveData> getSelectedTransferDestination() { + return mSelectedTransferDestination; + } + + public LiveData> getTransferDestinationError() { + return mTransferDestinationError; + } + + public LiveData isLoading() { + return mIsLoading; + } + + public void loadTransferDestinationList() { + mIsLoading.postValue(Boolean.TRUE); + mTransferMethodRepository.loadTransferMethods(new TransferMethodRepository.LoadTransferMethodListCallback() { + @Override + public void onTransferMethodListLoaded(List transferMethods) { + if (transferMethods != null) { + mTransferDestinationList.postValue(transferMethods); + } else { + mTransferDestinationList.setValue(new ArrayList()); + } + mIsLoading.postValue(Boolean.FALSE); + } + + @Override + public void onError(HyperwalletErrors errors) { + mIsLoading.postValue(Boolean.FALSE); + mTransferDestinationError.postValue(new Event<>(errors)); + } + }); + } + + public static class ListTransferDestinationViewModelFactory implements ViewModelProvider.Factory { + + private final TransferMethodRepository mTransferMethodRepository; + + public ListTransferDestinationViewModelFactory(@NonNull final TransferMethodRepository repository) { + mTransferMethodRepository = repository; + } + + @NonNull + @Override + public T create(@NonNull Class modelClass) { + if (modelClass.isAssignableFrom(ListTransferDestinationViewModel.class)) { + return (T) new ListTransferDestinationViewModel(mTransferMethodRepository); + } + throw new IllegalArgumentException( + "Expecting ViewModel class: " + ListTransferDestinationViewModel.class.getName()); + } + } +} diff --git a/transferui/src/main/res/layout/activity_create_transfer.xml b/transferui/src/main/res/layout/activity_create_transfer.xml new file mode 100644 index 000000000..ca216c095 --- /dev/null +++ b/transferui/src/main/res/layout/activity_create_transfer.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/transferui/src/main/res/layout/activity_list_transfer_destination.xml b/transferui/src/main/res/layout/activity_list_transfer_destination.xml new file mode 100644 index 000000000..e61d5e936 --- /dev/null +++ b/transferui/src/main/res/layout/activity_list_transfer_destination.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/transferui/src/main/res/layout/dialog_fragment_list_transfer_destination.xml b/transferui/src/main/res/layout/dialog_fragment_list_transfer_destination.xml new file mode 100644 index 000000000..1d3545ae6 --- /dev/null +++ b/transferui/src/main/res/layout/dialog_fragment_list_transfer_destination.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/transferui/src/main/res/layout/fragment_create_transfer.xml b/transferui/src/main/res/layout/fragment_create_transfer.xml new file mode 100644 index 000000000..d2eb13033 --- /dev/null +++ b/transferui/src/main/res/layout/fragment_create_transfer.xml @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +