# Conflicts: # app/build.gradle # app/src/main/java/com/wallet/crypto/trustapp/controller/Controller.javapull/2/head
@ -1 +1,38 @@ |
||||
# Trust Wallet for Android |
||||
# Trust - Ethereum Wallet for Android |
||||
|
||||
[![Build Status](https://travis-ci.org/TrustWallet/trust-wallet-android.svg?branch=master)](https://travis-ci.org/TrustWallet/trust-wallet-android) |
||||
[![License](https://img.shields.io/badge/license-GPL3-green.svg?style=flat)](https://github.com/fastlane/fastlane/blob/master/LICENSE) |
||||
|
||||
Welcome to Trust's open source Android app! |
||||
|
||||
## Getting Started |
||||
|
||||
1. Install latest Android Studio (>=3.0 RC 2). |
||||
2. Clone this repository. |
||||
3. Register with etherscan.io and populate the API keys in Controller.java |
||||
4. Build and run. |
||||
|
||||
Try the [app](https://play.google.com/store/apps/details?id=com.wallet.crypto.trustapp) on Google Play Store. |
||||
|
||||
## Contributing |
||||
|
||||
We intend for this project to be an educational resource: we are excited to |
||||
share our wins, mistakes, and methodology of android development as we work |
||||
in the open. Our primary focus is to continue improving the app for our users in |
||||
line with our roadmap. |
||||
|
||||
The best way to submit feedback and report bugs is to open a GitHub issue. |
||||
Please be sure to include your operating system, device, version number, and |
||||
steps to reproduce reported bugs. Keep in mind that all participants will be |
||||
expected to follow our code of conduct. |
||||
|
||||
## Code of Conduct |
||||
|
||||
We aim to share our knowledge and findings as we work daily to improve our |
||||
product, for our community, in a safe and open space. We work as we live, as |
||||
kind and considerate human beings who learn and grow from giving and receiving |
||||
positive, constructive feedback. We reserve the right to delete or ban any |
||||
behavior violating this base foundation of respect. |
||||
|
||||
Help with localization? |
||||
Here is a public link to join localization project: https://lokalise.co/signup/3947163159df13df851b51.98101647/all/ |
||||
|
@ -0,0 +1,44 @@ |
||||
package com.wallet.crypto.trustapp; |
||||
|
||||
import android.content.Context; |
||||
import android.support.test.InstrumentationRegistry; |
||||
|
||||
import com.wallet.crypto.trustapp.controller.PasswordManager; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import java.io.UnsupportedEncodingException; |
||||
import java.security.InvalidAlgorithmParameterException; |
||||
import java.security.InvalidKeyException; |
||||
import java.security.NoSuchAlgorithmException; |
||||
import java.security.spec.InvalidKeySpecException; |
||||
|
||||
import javax.crypto.BadPaddingException; |
||||
import javax.crypto.IllegalBlockSizeException; |
||||
import javax.crypto.NoSuchPaddingException; |
||||
|
||||
import static org.hamcrest.Matchers.is; |
||||
import static org.junit.Assert.assertThat; |
||||
|
||||
/** |
||||
* Created by marat on 11/14/17. |
||||
*/ |
||||
|
||||
public class PasswordManagerTest { |
||||
@Test |
||||
public void setGetPassword() throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, UnsupportedEncodingException, InvalidKeySpecException { |
||||
Context context = InstrumentationRegistry.getTargetContext(); |
||||
|
||||
PasswordManager.setPassword("myaddress", "mypassword", context); |
||||
assertThat(PasswordManager.getPassword("myaddress", context), is("mypassword")); |
||||
} |
||||
|
||||
@Test |
||||
public void setGetPasswordLegacy() throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, UnsupportedEncodingException, InvalidKeySpecException { |
||||
Context context = InstrumentationRegistry.getTargetContext(); |
||||
|
||||
PasswordManager.setPasswordLegacy("myaddress", "mypassword", context); |
||||
assertThat(PasswordManager.getPassword("myaddress", context), is("mypassword")); |
||||
} |
||||
} |
@ -1,34 +0,0 @@ |
||||
package com.wallet.crypto.trustapp; |
||||
|
||||
import android.content.Context; |
||||
import android.support.test.InstrumentationRegistry; |
||||
import android.support.test.rule.ActivityTestRule; |
||||
import android.support.test.runner.AndroidJUnit4; |
||||
|
||||
import com.wallet.crypto.trustapp.views.TransactionListActivity; |
||||
|
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
//import tools.fastlane.screengrab.Screengrab;
|
||||
|
||||
/** |
||||
* Instrumentation test, which will execute on an Android device. |
||||
* |
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
||||
*/ |
||||
@RunWith(AndroidJUnit4.class) |
||||
public class ScreengrabTest { |
||||
|
||||
@Rule |
||||
public ActivityTestRule<TransactionListActivity> activityRule = new ActivityTestRule<>(TransactionListActivity.class); |
||||
|
||||
@Test |
||||
public void takeTestScreenshot() throws Exception { |
||||
//Screengrab.screenshot("test_screenshot");
|
||||
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext(); |
||||
} |
||||
} |
@ -0,0 +1,145 @@ |
||||
package com.wallet.crypto.trustapp.views; |
||||
|
||||
|
||||
import android.support.test.espresso.ViewInteraction; |
||||
import android.support.test.rule.ActivityTestRule; |
||||
import android.support.test.runner.AndroidJUnit4; |
||||
import android.test.suitebuilder.annotation.LargeTest; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.view.ViewParent; |
||||
|
||||
import com.wallet.crypto.trustapp.R; |
||||
|
||||
import org.hamcrest.Description; |
||||
import org.hamcrest.Matcher; |
||||
import org.hamcrest.TypeSafeMatcher; |
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import tools.fastlane.screengrab.Screengrab; |
||||
|
||||
import static android.support.test.espresso.Espresso.onView; |
||||
import static android.support.test.espresso.action.ViewActions.click; |
||||
import static android.support.test.espresso.action.ViewActions.scrollTo; |
||||
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; |
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId; |
||||
import static android.support.test.espresso.matcher.ViewMatchers.withText; |
||||
import static org.hamcrest.Matchers.allOf; |
||||
|
||||
@LargeTest |
||||
@RunWith(AndroidJUnit4.class) |
||||
public class CreateAccountTest { |
||||
|
||||
@Rule |
||||
public ActivityTestRule<SplashActivity> mActivityTestRule = new ActivityTestRule<>(SplashActivity.class); |
||||
|
||||
@Test |
||||
public void createAccountTest() { |
||||
Screengrab.screenshot("intro1"); |
||||
ViewInteraction appCompatImageButton = onView( |
||||
allOf(withId(R.id.next), |
||||
childAtPosition( |
||||
allOf(withId(R.id.bottomContainer), |
||||
childAtPosition( |
||||
withId(R.id.bottom), |
||||
1)), |
||||
3), |
||||
isDisplayed())); |
||||
|
||||
appCompatImageButton.perform(click()); |
||||
|
||||
Screengrab.screenshot("intro2"); |
||||
ViewInteraction appCompatImageButton2 = onView( |
||||
allOf(withId(R.id.next), |
||||
childAtPosition( |
||||
allOf(withId(R.id.bottomContainer), |
||||
childAtPosition( |
||||
withId(R.id.bottom), |
||||
1)), |
||||
3), |
||||
isDisplayed())); |
||||
appCompatImageButton2.perform(click()); |
||||
|
||||
Screengrab.screenshot("intro3"); |
||||
ViewInteraction appCompatButton = onView( |
||||
allOf(withId(R.id.done), withText("DONE"), |
||||
childAtPosition( |
||||
allOf(withId(R.id.bottomContainer), |
||||
childAtPosition( |
||||
withId(R.id.bottom), |
||||
1)), |
||||
4), |
||||
isDisplayed())); |
||||
appCompatButton.perform(click()); |
||||
|
||||
ViewInteraction appCompatButton2 = onView( |
||||
allOf(withId(R.id.create_account_button), withText("Create"), |
||||
childAtPosition( |
||||
childAtPosition( |
||||
withId(android.R.id.content), |
||||
0), |
||||
0), |
||||
isDisplayed())); |
||||
appCompatButton2.perform(click()); |
||||
|
||||
ViewInteraction appCompatButton3 = onView( |
||||
allOf(withId(R.id.later_button), withText("Do it later"), |
||||
childAtPosition( |
||||
childAtPosition( |
||||
withId(android.R.id.content), |
||||
0), |
||||
0), |
||||
isDisplayed())); |
||||
appCompatButton3.perform(click()); |
||||
|
||||
ViewInteraction appCompatButton4 = onView( |
||||
allOf(withId(android.R.id.button1), withText("OK"), |
||||
childAtPosition( |
||||
childAtPosition( |
||||
withId(R.id.buttonPanel), |
||||
0), |
||||
3))); |
||||
appCompatButton4.perform(scrollTo(), click()); |
||||
|
||||
// Added a sleep statement to match the app's execution delay.
|
||||
// The recommended way to handle such scenarios is to use Espresso idling resources:
|
||||
// https://google.github.io/android-testing-support-library/docs/espresso/idling-resource/index.html
|
||||
try { |
||||
Thread.sleep(10000); |
||||
} catch (InterruptedException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
|
||||
ViewInteraction bottomNavigationItemView = onView( |
||||
allOf(withId(R.id.navigation_send), |
||||
childAtPosition( |
||||
childAtPosition( |
||||
withId(R.id.navigation), |
||||
0), |
||||
0), |
||||
isDisplayed())); |
||||
bottomNavigationItemView.perform(click()); |
||||
|
||||
} |
||||
|
||||
private static Matcher<View> childAtPosition( |
||||
final Matcher<View> parentMatcher, final int position) { |
||||
|
||||
return new TypeSafeMatcher<View>() { |
||||
@Override |
||||
public void describeTo(Description description) { |
||||
description.appendText("Child at position " + position + " in parent "); |
||||
parentMatcher.describeTo(description); |
||||
} |
||||
|
||||
@Override |
||||
public boolean matchesSafely(View view) { |
||||
ViewParent parent = view.getParent(); |
||||
return parent instanceof ViewGroup && parentMatcher.matches(parent) |
||||
&& view.equals(((ViewGroup) parent).getChildAt(position)); |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
package com.wallet.crypto.trustapp.controller; |
||||
|
||||
import com.wallet.crypto.trustapp.model.CMTicker; |
||||
|
||||
import java.util.List; |
||||
|
||||
import retrofit2.Call; |
||||
import retrofit2.http.GET; |
||||
|
||||
/** |
||||
* Created by marat on 11/13/17. |
||||
*/ |
||||
|
||||
public interface CoinmarketService { |
||||
@GET("/v1/ticker/ethereum") |
||||
Call<List<CMTicker>> getEthereumPrice(); |
||||
} |
@ -0,0 +1,17 @@ |
||||
package com.wallet.crypto.trustapp.controller; |
||||
|
||||
import com.wallet.crypto.trustapp.model.EPAddressInfo; |
||||
|
||||
import retrofit2.Call; |
||||
import retrofit2.http.GET; |
||||
import retrofit2.http.Query; |
||||
import retrofit2.http.Path; |
||||
|
||||
/** |
||||
* Created by marat on 11/16/17. |
||||
*/ |
||||
|
||||
public interface EthplorerService { |
||||
@GET("/getAddressInfo/{address}") |
||||
Call<EPAddressInfo> getAddressInfo(@Path("address") String address, @Query("apiKey") String apiKey); |
||||
} |
@ -0,0 +1,34 @@ |
||||
package com.wallet.crypto.trustapp.model; |
||||
|
||||
import com.google.gson.annotations.SerializedName; |
||||
|
||||
/** |
||||
* Created by marat on 11/13/17. |
||||
{ |
||||
"id": "ethereum", |
||||
"name": "Ethereum", |
||||
"symbol": "ETH", |
||||
"rank": "2", |
||||
"price_usd": "314.862", |
||||
"price_btc": "0.0474923", |
||||
"24h_volume_usd": "1328580000.0", |
||||
"market_cap_usd": "30133198205.0", |
||||
"available_supply": "95702874.0", |
||||
"total_supply": "95702874.0", |
||||
"max_supply": null, |
||||
"percent_change_1h": "-0.1", |
||||
"percent_change_24h": "1.87", |
||||
"percent_change_7d": "4.21", |
||||
"last_updated": "1510589050" |
||||
} |
||||
*/ |
||||
|
||||
public class CMTicker { |
||||
@SerializedName("price_usd") |
||||
private String priceUsd; |
||||
|
||||
public String getPriceUsd() { |
||||
return priceUsd; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,98 @@ |
||||
package com.wallet.crypto.trustapp.model; |
||||
|
||||
import com.google.gson.annotations.SerializedName; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* Created by marat on 11/16/17. |
||||
*/ |
||||
|
||||
/* This represents the following json |
||||
{ |
||||
"address": "0x0122374ddd61ebdbe487f27225c8d55a96688714", |
||||
"ETH": { |
||||
"balance": 0.0081799448, |
||||
"totalIn": 23.9400569448, |
||||
"totalOut": 23.931877 |
||||
}, |
||||
"countTxs": 16, |
||||
"tokens": [{ |
||||
"tokenInfo": { |
||||
"address": "0xab95e915c123fded5bdfb6325e35ef5515f1ea69", |
||||
"name": "XENON", |
||||
"decimals": 18, |
||||
"symbol": "XNN", |
||||
"totalSupply": "1000000000000000000000000000", |
||||
"owner": "0x", |
||||
"lastUpdated": 1510850050, |
||||
"issuancesCount": 0, |
||||
"holdersCount": 756611, |
||||
"description": "XenonNetwork (http://xenon.network/), an enterprise-scale blockchain launching in July 2018 begins a massive distribution of their native Xenon (XNN) ERC-20 compatible tokens to over 400,000 active ethereum addresses at the beginning of October. In addition to this, a similar distribution to bitcoin holders will occur in November, followed by a proof-of-individuality public token distribution from November through to June 2018.\n\nhttp://xenon.network", |
||||
"price": false |
||||
}, |
||||
"balance": 6.9576614445292e+20, |
||||
"totalIn": 0, |
||||
"totalOut": 0 |
||||
}, { |
||||
"tokenInfo": { |
||||
"address": "0x0cf0ee63788a0849fe5297f3407f701e122cc023", |
||||
"name": "DATAcoin", |
||||
"decimals": 18, |
||||
"symbol": "DATA", |
||||
"totalSupply": "987154514000000000000000000", |
||||
"owner": "0x1bb7804d12fa4f70ab63d0bbe8cb0b1992694338", |
||||
"lastUpdated": 1510851220, |
||||
"totalIn": 2.165e+26, |
||||
"totalOut": 2.165e+26, |
||||
"issuancesCount": 0, |
||||
"holdersCount": 433497, |
||||
"price": false |
||||
}, |
||||
"balance": 1.0541017210196e+18, |
||||
"totalIn": 0, |
||||
"totalOut": 0 |
||||
}, { |
||||
"tokenInfo": { |
||||
"address": "0xd0a4b8946cb52f0661273bfbc6fd0e0c75fc6433", |
||||
"name": "Storm Token", |
||||
"decimals": "18", |
||||
"symbol": "STORM", |
||||
"totalSupply": "8422653913958765221271563784", |
||||
"owner": "0x00250bf60e31c4ec7e8c04bcca4af8e294306e25", |
||||
"lastUpdated": 1510845529, |
||||
"issuancesCount": 0, |
||||
"holdersCount": 974, |
||||
"price": false |
||||
}, |
||||
"balance": 2.156e+22, |
||||
"totalIn": 0, |
||||
"totalOut": 0 |
||||
}, { |
||||
"tokenInfo": { |
||||
"address": "0x519475b31653e46d20cd09f9fdcf3b12bdacb4f5", |
||||
"name": "VIU", |
||||
"decimals": "18", |
||||
"symbol": "VIU", |
||||
"totalSupply": "1000000000000000000000000000", |
||||
"owner": "0x", |
||||
"lastUpdated": 1510851386, |
||||
"issuancesCount": 0, |
||||
"holdersCount": 441605, |
||||
"price": false |
||||
}, |
||||
"balance": 1.984985648e+20, |
||||
"totalIn": 0, |
||||
"totalOut": 0 |
||||
}] |
||||
} |
||||
*/ |
||||
|
||||
public class EPAddressInfo { |
||||
@SerializedName("tokens") |
||||
private List<EPToken> tokens; |
||||
|
||||
public List<EPToken> getTokens() { |
||||
return tokens; |
||||
} |
||||
} |
@ -0,0 +1,47 @@ |
||||
package com.wallet.crypto.trustapp.model; |
||||
|
||||
import com.google.gson.annotations.SerializedName; |
||||
|
||||
/** |
||||
* Created by marat on 11/16/17. |
||||
* |
||||
*/ |
||||
|
||||
/* Represents the following JSON |
||||
{ |
||||
"tokenInfo": { |
||||
"address": "0x0cf0ee63788a0849fe5297f3407f701e122cc023", |
||||
"name": "DATAcoin", |
||||
"decimals": 18, |
||||
"symbol": "DATA", |
||||
"totalSupply": "987154514000000000000000000", |
||||
"owner": "0x1bb7804d12fa4f70ab63d0bbe8cb0b1992694338", |
||||
"lastUpdated": 1510851220, |
||||
"totalIn": 2.165e+26, |
||||
"totalOut": 2.165e+26, |
||||
"issuancesCount": 0, |
||||
"holdersCount": 433497, |
||||
"price": false |
||||
}, |
||||
"balance": 1.0541017210196e+18, |
||||
"totalIn": 0, |
||||
"totalOut": 0 |
||||
} |
||||
*/ |
||||
|
||||
public class EPToken { |
||||
|
||||
@SerializedName("tokenInfo") |
||||
private EPTokenInfo tokenInfo; |
||||
|
||||
@SerializedName("balance") |
||||
private double balance; |
||||
|
||||
public EPTokenInfo getTokenInfo() { |
||||
return tokenInfo; |
||||
} |
||||
|
||||
public double getBalance() { |
||||
return balance; |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
package com.wallet.crypto.trustapp.model; |
||||
|
||||
import com.google.gson.annotations.SerializedName; |
||||
|
||||
/** |
||||
* Created by marat on 11/16/17. |
||||
*/ |
||||
|
||||
/* Represents the following JSON |
||||
{ |
||||
"address": "0x0cf0ee63788a0849fe5297f3407f701e122cc023", |
||||
"name": "DATAcoin", |
||||
"decimals": 18, |
||||
"symbol": "DATA", |
||||
"totalSupply": "987154514000000000000000000", |
||||
"owner": "0x1bb7804d12fa4f70ab63d0bbe8cb0b1992694338", |
||||
"lastUpdated": 1510851220, |
||||
"totalIn": 2.165e+26, |
||||
"totalOut": 2.165e+26, |
||||
"issuancesCount": 0, |
||||
"holdersCount": 433497, |
||||
"price": false |
||||
} |
||||
*/ |
||||
|
||||
public class EPTokenInfo { |
||||
@SerializedName("address") |
||||
private String address; |
||||
|
||||
@SerializedName("name") |
||||
private String name; |
||||
|
||||
@SerializedName("symbol") |
||||
private String symbol; |
||||
|
||||
@SerializedName("decimals") |
||||
private int decimals; |
||||
|
||||
public String getAddress() { |
||||
return address; |
||||
} |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public String getSymbol() { |
||||
return symbol; |
||||
} |
||||
|
||||
public int getDecimals() { |
||||
return decimals; |
||||
} |
||||
} |
@ -0,0 +1,187 @@ |
||||
package com.wallet.crypto.trustapp.views; |
||||
|
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.os.Bundle; |
||||
import android.support.annotation.NonNull; |
||||
import android.support.design.widget.FloatingActionButton; |
||||
import android.support.design.widget.Snackbar; |
||||
import android.support.v7.app.ActionBar; |
||||
import android.support.v7.app.AppCompatActivity; |
||||
import android.support.v7.widget.RecyclerView; |
||||
import android.support.v7.widget.Toolbar; |
||||
import android.util.Log; |
||||
import android.view.LayoutInflater; |
||||
import android.view.MenuItem; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.TextView; |
||||
import android.widget.Toast; |
||||
|
||||
import com.wallet.crypto.trustapp.R; |
||||
import com.wallet.crypto.trustapp.controller.Controller; |
||||
import com.wallet.crypto.trustapp.controller.EthplorerService; |
||||
import com.wallet.crypto.trustapp.model.EPAddressInfo; |
||||
import com.wallet.crypto.trustapp.model.EPToken; |
||||
import com.wallet.crypto.trustapp.model.EPTokenInfo; |
||||
|
||||
import java.math.BigDecimal; |
||||
import java.math.RoundingMode; |
||||
import java.util.List; |
||||
|
||||
import retrofit2.Call; |
||||
import retrofit2.Callback; |
||||
import retrofit2.Response; |
||||
import retrofit2.Retrofit; |
||||
import retrofit2.converter.gson.GsonConverterFactory; |
||||
|
||||
public class TokenListActivity extends AppCompatActivity { |
||||
|
||||
private static String TAG = "TOKENS"; |
||||
private String mAddress; |
||||
|
||||
@Override |
||||
protected void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
setContentView(R.layout.activity_token_list); |
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); |
||||
setSupportActionBar(toolbar); |
||||
|
||||
ActionBar actionBar = getSupportActionBar(); |
||||
if (actionBar != null) { |
||||
actionBar.setDisplayHomeAsUpEnabled(true); |
||||
} |
||||
|
||||
mAddress = getIntent().getStringExtra(Controller.KEY_ADDRESS); |
||||
|
||||
RecyclerView recyclerView = findViewById(R.id.token_list); |
||||
|
||||
setupRecyclerView(recyclerView); |
||||
} |
||||
|
||||
private void setupRecyclerView(final @NonNull RecyclerView recyclerView) { |
||||
try { |
||||
Retrofit retrofit = new Retrofit.Builder() |
||||
.addConverterFactory(GsonConverterFactory.create()) |
||||
.baseUrl("https://api.ethplorer.io") |
||||
.build(); |
||||
|
||||
EthplorerService service = retrofit.create(EthplorerService.class); |
||||
|
||||
Call<EPAddressInfo> call = service.getAddressInfo(mAddress, "freekey"); |
||||
|
||||
call.enqueue(new Callback<EPAddressInfo>() { |
||||
|
||||
@Override |
||||
public void onResponse(Call<EPAddressInfo> call, Response<EPAddressInfo> response) { |
||||
try { |
||||
Log.d(TAG, Integer.toString(response.body().getTokens().size())); |
||||
EPAddressInfo addressInfo = response.body(); |
||||
recyclerView.setAdapter(new SimpleItemRecyclerViewAdapter(addressInfo.getTokens())); |
||||
} catch (Exception e) { |
||||
Log.e(TAG, e.getLocalizedMessage()); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onFailure(Call<EPAddressInfo> call, Throwable t) { |
||||
Log.e("ERROR", t.toString()); |
||||
Toast.makeText(TokenListActivity.this.getApplicationContext(), "Error contacting token service. Check internet connection.", Toast.LENGTH_SHORT).show(); |
||||
} |
||||
}); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
public class SimpleItemRecyclerViewAdapter |
||||
extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> { |
||||
|
||||
private final List<EPToken> mValues; |
||||
|
||||
public SimpleItemRecyclerViewAdapter(List<EPToken> items) { |
||||
mValues = items; |
||||
} |
||||
|
||||
@Override |
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { |
||||
View view = LayoutInflater.from(parent.getContext()) |
||||
.inflate(R.layout.token_list_content, parent, false); |
||||
return new ViewHolder(view); |
||||
} |
||||
|
||||
@Override |
||||
public void onBindViewHolder(final ViewHolder holder, int position) { |
||||
holder.mItem = mValues.get(position); |
||||
|
||||
EPToken token = holder.mItem; |
||||
final EPTokenInfo info = token.getTokenInfo(); |
||||
|
||||
try { |
||||
holder.mNameView.setText(info.getName()); |
||||
holder.mSymbolView.setText(info.getSymbol()); |
||||
|
||||
BigDecimal balance = new BigDecimal(token.getBalance()); |
||||
BigDecimal decimalDivisor = new BigDecimal(Math.pow(10, info.getDecimals())); |
||||
balance = info.getDecimals() > 0 ? balance.divide(decimalDivisor) : balance; |
||||
balance = balance.setScale(2, RoundingMode.HALF_UP); |
||||
holder.mBalanceView.setText(balance.toString()); |
||||
|
||||
holder.mView.setOnClickListener(new View.OnClickListener() { |
||||
@Override |
||||
public void onClick(View v) { |
||||
Context context = v.getContext(); |
||||
Intent intent = new Intent(context, SendActivity.class); |
||||
intent.putExtra(SendActivity.EXTRA_SENDING_TOKENS, true); |
||||
intent.putExtra(SendActivity.EXTRA_CONTRACT_ADDRESS, info.getAddress()); |
||||
intent.putExtra(SendActivity.EXTRA_SYMBOL, info.getSymbol()); |
||||
intent.putExtra(SendActivity.EXTRA_DECIMALS, info.getDecimals()); |
||||
|
||||
context.startActivity(intent); |
||||
} |
||||
}); |
||||
} catch (Exception e) { |
||||
holder.mNameView.setText("N/A"); |
||||
holder.mSymbolView.setText("N/A"); |
||||
holder.mBalanceView.setText("-"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int getItemCount() { |
||||
return mValues.size(); |
||||
} |
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder { |
||||
public final View mView; |
||||
public final TextView mNameView; |
||||
public final TextView mSymbolView; |
||||
public final TextView mBalanceView; |
||||
|
||||
public EPToken mItem; |
||||
|
||||
public ViewHolder(View view) { |
||||
super(view); |
||||
mView = view; |
||||
mNameView = view.findViewById(R.id.name); |
||||
mSymbolView = view.findViewById(R.id.symbol); |
||||
mBalanceView = view.findViewById(R.id.balance); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return super.toString(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean onOptionsItemSelected(MenuItem item) { |
||||
int id = item.getItemId(); |
||||
if (id == android.R.id.home) { |
||||
finish(); |
||||
return true; |
||||
} |
||||
return super.onOptionsItemSelected(item); |
||||
} |
||||
} |
After Width: | Height: | Size: 669 B |
After Width: | Height: | Size: 489 B |
After Width: | Height: | Size: 986 B |
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,25 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
tools:context="com.wallet.crypto.trustapp.views.TokenListActivity"> |
||||
|
||||
<android.support.design.widget.AppBarLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:theme="@style/AppTheme.AppBarOverlay"> |
||||
|
||||
<android.support.v7.widget.Toolbar |
||||
android:id="@+id/toolbar" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="?attr/actionBarSize" |
||||
android:background="?attr/colorPrimary" |
||||
app:popupTheme="@style/AppTheme.PopupOverlay" /> |
||||
|
||||
</android.support.design.widget.AppBarLayout> |
||||
|
||||
<include layout="@layout/content_token_list" /> |
||||
|
||||
</android.support.design.widget.CoordinatorLayout> |
@ -0,0 +1,24 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" |
||||
tools:context="com.wallet.crypto.trustapp.views.TokenListActivity" |
||||
tools:showIn="@layout/activity_token_list"> |
||||
|
||||
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:id="@+id/token_list" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:layout_marginTop="8dp" |
||||
android:layout_marginLeft="0dp" |
||||
android:layout_marginRight="0dp" |
||||
app:layoutManager="LinearLayoutManager" |
||||
tools:context="com.wallet.crypto.trustapp.views.TokenListActivity" |
||||
tools:listitem="@layout/token_list_content" /> |
||||
|
||||
</android.support.constraint.ConstraintLayout> |
@ -0,0 +1,49 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="horizontal" |
||||
android:weightSum="2"> |
||||
|
||||
<ImageView |
||||
android:id="@+id/logo" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:src="@mipmap/token_logo" |
||||
android:layout_alignParentLeft="true" |
||||
android:layout_alignParentStart="true" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/name" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_weight="1" |
||||
android:maxLines="1" |
||||
android:text="Trust" |
||||
android:textAppearance="?attr/textAppearanceListItem" |
||||
android:layout_toRightOf="@id/logo" |
||||
android:layout_alignParentTop="true" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/symbol" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_toRightOf="@id/logo" |
||||
android:layout_below="@+id/name" |
||||
android:layout_weight="1" |
||||
android:maxLines="1" |
||||
android:text="TRST" |
||||
android:textAppearance="?attr/textAppearanceListItem" |
||||
android:textSize="11dp" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/balance" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_weight="1" |
||||
android:layout_marginRight="13dp" |
||||
android:layout_marginEnd="13dp" |
||||
android:layout_centerVertical="true" |
||||
android:layout_alignParentRight="true" |
||||
android:layout_alignParentEnd="true" /> |
||||
</RelativeLayout> |
@ -1,19 +0,0 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
||||
<item |
||||
android:id="@+id/navigation_home" |
||||
android:icon="@drawable/ic_home_black_24dp" |
||||
android:title="@string/title_home" /> |
||||
|
||||
<item |
||||
android:id="@+id/navigation_dashboard" |
||||
android:icon="@drawable/ic_dashboard_black_24dp" |
||||
android:title="@string/title_dashboard" /> |
||||
|
||||
<item |
||||
android:id="@+id/navigation_notifications" |
||||
android:icon="@drawable/ic_notifications_black_24dp" |
||||
android:title="@string/title_notifications" /> |
||||
|
||||
</menu> |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 859 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 20 KiB |
@ -0,0 +1,15 @@ |
||||
# remove the leading '#' to uncomment lines |
||||
|
||||
app_package_name 'com.wallet.crypto.trustapp' |
||||
# use_tests_in_packages ['your.screenshot.tests.package'] |
||||
|
||||
app_apk_path './app/build/outputs/apk/app-debug.apk' |
||||
tests_apk_path './app/build/outputs/apk/app-debug-androidTest.apk' |
||||
|
||||
locales ['en-US'] |
||||
|
||||
# clear all previously generated screenshots in your local output directory before creating new ones |
||||
clear_previous_screenshots true |
||||
|
||||
# For more information about all available options run |
||||
# fastlane screengrab --help |