Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1b44713
HW-52585 UI - Receipt Details
Jun 12, 2019
6f222bd
remove unnecessary configs
Jun 12, 2019
4d87981
formatted amounts
Jun 12, 2019
5ffbcb3
remove static
Jun 12, 2019
30d585a
fixed variable name
Jun 12, 2019
c692629
refactored methods
Jun 13, 2019
f7cf238
Merge remote-tracking branch 'remotes/origin/development' into featur…
Jun 13, 2019
8987e71
added 12-HR to 24-HR and vice-versa formatter
Jun 14, 2019
5c00306
granular code {^__^}
Jun 14, 2019
1241fdc
convention
Jun 14, 2019
8d9138a
fix amount and transfer amount reversed
Jun 14, 2019
9d743d1
Merge remote-tracking branch 'remotes/origin/development' into featur…
Jun 14, 2019
465ecb9
fix date localization formatting to receipt views
Jun 17, 2019
bf61a05
update background effect to use ripple, added todos for currency form…
Jun 17, 2019
8163d53
ui specs changes
Jun 17, 2019
cf23ee8
update notes value layout
Jun 17, 2019
83d424d
try remove lint exception
Jun 17, 2019
972dd0c
fixed lint
Jun 17, 2019
7ddf49d
by design decision removing binding classes into duplicate code
Jun 18, 2019
2be481e
synced with core sdk
Jun 18, 2019
7443ad6
fixing typo
fmattos-hw Jun 18, 2019
ff14349
revert rename
Jun 18, 2019
43b351f
Automation for receipt details and receipt network retry (#43)
skoong Jun 18, 2019
9a87a91
added finalizer identifiers
Jun 18, 2019
1127fc1
Merge branch 'development' into feature/HW-52585-ui-receipt-details
skoong Jun 18, 2019
ca29ad4
Updating response throttling
skoong Jun 18, 2019
2ac6d59
renamed receipts to user list specific
Jun 19, 2019
680b4c6
changed singletone to immutable data source factory
Jun 19, 2019
0f5e5d5
generalized view model so that we can reuse the user receipt view for…
Jun 19, 2019
4082b82
added data source for prepaid card and test equivalent unit test
Jun 19, 2019
109db66
initial integration of ppc and user receipts
Jun 19, 2019
5d28e64
Merge remote-tracking branch 'remotes/origin/development' into featur…
Jun 19, 2019
77ade14
fixed test
Jun 19, 2019
21175ff
removed extra import
Jun 21, 2019
7cf603c
local review
Jun 24, 2019
d8fa65b
Merge remote-tracking branch 'remotes/origin/development' into featur…
Jun 24, 2019
d4c97ea
change data
Jun 25, 2019
e47433c
fix javadocs
Jun 26, 2019
73fd500
removed unused exception in test
Jun 27, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<ListPrepaidCardReceiptActivity> mActivityTestRule =
new ActivityTestRule<ListPrepaidCardReceiptActivity>(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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<ListReceiptActivity> mActivityTestRule =
new ActivityTestRule<>(ListReceiptActivity.class, true, false);
public ActivityTestRule<ListUserReceiptActivity> mActivityTestRule =
new ActivityTestRule<>(ListUserReceiptActivity.class, true, false);

@Before
public void setup() {
Expand All @@ -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());
Expand Down Expand Up @@ -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
Expand Down
17 changes: 11 additions & 6 deletions receipt/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@
<uses-permission android:name="android.permission.INTERNET"/>

<application
android:networkSecurityConfig="@xml/network_security_config" tools:targetApi="n">
<activity android:name=".view.ReceiptDetailActivity"
android:label="@string/title_activity_receipt_detail"
android:theme="@style/AppTheme.NoActionBar"/>

android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="n">
<activity
android:name=".view.ListPrepaidCardReceiptActivity"
android:label="@string/title_activity_receipt_list"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name=".view.ReceiptDetailActivity"
android:label="@string/title_activity_receipt_detail"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name=".view.ListReceiptActivity"
android:name=".view.ListUserReceiptActivity"
android:label="@string/title_activity_receipt_list"
android:theme="@style/AppTheme.NoActionBar"/>
</application>
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Date, Receipt> {

private static final int YEAR_BEFORE_NOW = -1;

private final Calendar mCalendarYearBeforeNow;
private final String mToken;
private final MutableLiveData<Event<HyperwalletErrors>> mErrors = new MutableLiveData<>();
private final MutableLiveData<Boolean> mIsFetchingData = new MutableLiveData<>();
private PageKeyedDataSource.LoadCallback<Date, Receipt> mLoadAfterCallback;
private PageKeyedDataSource.LoadParams<Date> mLoadAfterParams;
private PageKeyedDataSource.LoadInitialCallback<Date, Receipt> mLoadInitialCallback;
private PageKeyedDataSource.LoadInitialParams<Date> 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<Date> params,
@NonNull final LoadInitialCallback<Date, Receipt> 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<HyperwalletPageList<Receipt>>() {
@Override
public void onSuccess(@Nullable HyperwalletPageList<Receipt> 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<Date> params,
@NonNull final LoadCallback<Date, Receipt> callback) {
}

/**
* @see PageKeyedDataSource#loadAfter(LoadParams, LoadCallback)
*/
@Override
public void loadAfter(@NonNull final LoadParams<Date> params, @NonNull final LoadCallback<Date, Receipt> 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<HyperwalletPageList<Receipt>>() {
@Override
public void onSuccess(@Nullable HyperwalletPageList<Receipt> 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<Event<HyperwalletErrors>> getErrors() {
return mErrors;
}

LiveData<Boolean> isFetchingData() {
return mIsFetchingData;
}

Hyperwallet getHyperwallet() {
return Hyperwallet.getDefault();
}

private Date getNextDate(@Nullable final HyperwalletPageList<Receipt> 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();
}
}
Loading