diff --git a/app/build.gradle b/app/build.gradle
index 44270e6..f8fa21f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,6 +1,8 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt' // add this line
+
kapt {
generateStubs = true
@@ -15,8 +17,8 @@ android {
applicationId "cy.agorise.crystalwallet"
minSdkVersion 21
targetSdkVersion 27
- versionCode 4
- versionName "0.4M.alpha"
+ versionCode 3
+ versionName "0.3M.alpha"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b185b0d..8739183 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
-1) {
diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/BoardActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/BoardActivity.java
index 815e70f..4a8a2de 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/activities/BoardActivity.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/activities/BoardActivity.java
@@ -98,6 +98,14 @@ public class BoardActivity extends CustomActivity {
File photoDirectory;
+ /*
+ * For the window animation
+ * */
+ private MediaPlayer mediaPlayer;
+
+
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -170,7 +178,7 @@ public class BoardActivity extends CustomActivity {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//Log.d(TAG,"surfaceCreated");
- MediaPlayer mediaPlayer = MediaPlayer.create(BoardActivity.this, R.raw.appbar_background);
+ mediaPlayer = MediaPlayer.create(BoardActivity.this, R.raw.appbar_background);
mediaPlayer.setDisplay(mSurfaceView.getHolder());
mediaPlayer.setLooping(true);
mediaPlayer.start();
@@ -271,6 +279,17 @@ public class BoardActivity extends CustomActivity {
loadUserImage();
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ //Release the media player
+ if(mediaPlayer!=null){
+ mediaPlayer.release();
+ mediaPlayer = null;
+ }
+ }
+
public void loadUserImage(){
//Search for a existing photo
File photoFile = new File(photoDirectory + File.separator + "photo.png");
diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt b/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt
index 1f3f535..fdeaf06 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt
+++ b/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt
@@ -200,6 +200,7 @@ class CreateSeedActivity : CustomActivity() {
val intent = Intent(applicationContext, BackupSeedActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
intent.putExtra("SEED_ID", accountSeed.id)
+ intent.putExtra("newAccount", true)
startActivity(intent)
}
else if (request.status == ValidateCreateBitsharesAccountRequest.StatusCode.ACCOUNT_EXIST) {
diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/CryptoNetAccountSettingsActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/CryptoNetAccountSettingsActivity.java
index 460cfdc..429f6f4 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/activities/CryptoNetAccountSettingsActivity.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/activities/CryptoNetAccountSettingsActivity.java
@@ -56,6 +56,14 @@ public class CryptoNetAccountSettingsActivity extends AppCompatActivity{
private CryptoNetAccount cryptoNetAccount;
+ /*
+ * For the window animation
+ * */
+ private MediaPlayer mediaPlayer;
+
+
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -98,7 +106,7 @@ public class CryptoNetAccountSettingsActivity extends AppCompatActivity{
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//Log.d(TAG,"surfaceCreated");
- MediaPlayer mediaPlayer = MediaPlayer.create(CryptoNetAccountSettingsActivity.this, R.raw.appbar_background);
+ mediaPlayer = MediaPlayer.create(CryptoNetAccountSettingsActivity.this, R.raw.appbar_background);
mediaPlayer.setDisplay(mSurfaceView.getHolder());
mediaPlayer.setLooping(true);
mediaPlayer.start();
@@ -121,6 +129,19 @@ public class CryptoNetAccountSettingsActivity extends AppCompatActivity{
}
}
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ //Release the media player
+ if(mediaPlayer!=null){
+ mediaPlayer.release();
+ mediaPlayer = null;
+ }
+ }
+
+
private class SettingsPagerAdapter extends FragmentStatePagerAdapter {
SettingsPagerAdapter(FragmentManager fm) {
super(fm);
diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/ImportSeedActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/ImportSeedActivity.java
index c583459..cfac83f 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/activities/ImportSeedActivity.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/activities/ImportSeedActivity.java
@@ -1,10 +1,12 @@
package cy.agorise.crystalwallet.activities;
+import android.app.Activity;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
+import android.text.TextWatcher;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
@@ -14,6 +16,7 @@ import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnTextChanged;
import cy.agorise.crystalwallet.R;
+import cy.agorise.crystalwallet.dialogs.material.CrystalLoading;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestListener;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.requestmanagers.ValidateImportBitsharesAccountRequest;
@@ -53,6 +56,8 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
@BindView(R.id.btnCancel)
Button btnCancel;
+ final Activity activity = this;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -60,12 +65,136 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
ButterKnife.bind(this);
- btnImport.setEnabled(false);
+ /*
+ * Initially the button CREATE WALLET should be disabled
+ * */
+ disableCreate();
+
+ /*
+ * When a text change in any of the fields
+ * */
+ etPin.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) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+
+ /*
+ * If all is ready to continue enable the button, contrarie case disable it
+ * */
+ if(allFieldsAreFill()){
+ enableCreate();
+ }
+ else{
+ disableCreate();
+ }
+ }
+ });
+ etPinConfirmation.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) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+
+ /*
+ * If all is ready to continue enable the button, contrarie case disable it
+ * */
+ if(allFieldsAreFill()){
+ enableCreate();
+ }
+ else{
+ disableCreate();
+ }
+ }
+ });
+ etSeedWords.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) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+
+ /*
+ * If all is ready to continue enable the button, contrarie case disable it
+ * */
+ if(allFieldsAreFill()){
+ enableCreate();
+ }
+ else{
+ disableCreate();
+ }
+ }
+ });
+ etAccountName.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) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+
+ /*
+ * If all is ready to continue enable the button, contrarie case disable it
+ * */
+ if(allFieldsAreFill()){
+ enableCreate();
+ }
+ else{
+ disableCreate();
+ }
+ }
+ });
+
accountSeedViewModel = ViewModelProviders.of(this).get(AccountSeedViewModel.class);
importSeedValidator = new ImportSeedValidator(this.getApplicationContext(),etPin,etPinConfirmation,etAccountName,etSeedWords);
importSeedValidator.setListener(this);
}
+
+ /*
+ * Method to validate if all the fields are fill
+ * */
+ private boolean allFieldsAreFill(){
+
+ boolean complete = false;
+ if( etPin.getText().toString().trim().compareTo("")!=0 &&
+ etPinConfirmation.getText().toString().trim().compareTo("")!=0 &&
+ etSeedWords.getText().toString().trim().compareTo("")!=0 &&
+ etAccountName.getText().toString().trim().compareTo("")!=0){
+ complete = true;
+ }
+ return complete;
+ }
+
@OnTextChanged(value = R.id.etPin,
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void afterPinChanged(Editable editable) {
@@ -102,12 +231,25 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
if (this.importSeedValidator.isValid()) {
+
+ /*
+ * Loading dialog
+ * */
+ final CrystalLoading crystalLoading = new CrystalLoading(activity);
+ crystalLoading.show();
+
final ValidateImportBitsharesAccountRequest validatorRequest =
new ValidateImportBitsharesAccountRequest(etAccountName.getText().toString(), etSeedWords.getText().toString(), getApplicationContext(), true);
validatorRequest.setListener(new CryptoNetInfoRequestListener() {
@Override
public void onCarryOut() {
+
+ /*
+ * Hide the loading dialog
+ * */
+ crystalLoading.dismiss();
+
if (!validatorRequest.getStatus().equals(ValidateImportBitsharesAccountRequest.StatusCode.SUCCEEDED)) {
String errorText = "An error ocurred attempting to import the account";
@@ -182,9 +324,9 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
}
if (activity.importSeedValidator.isValid()){
- btnImport.setEnabled(true);
+ enableCreate();
} else {
- btnImport.setEnabled(false);
+ disableCreate();
}
}
@@ -203,4 +345,31 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
//tvSeedWordsError.setText(field.getMessage());
}
}
+
+
+ /*
+ * Enable create button
+ * */
+ private void enableCreate() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ btnImport.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
+ btnImport.setEnabled(true);
+ }
+ });
+ }
+
+ /*
+ * Disable create button
+ * */
+ private void disableCreate() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ btnImport.setEnabled(false);
+ btnImport.setBackground(getDrawable(R.drawable.disable_style));
+ }
+ });
+ }
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java
index f0e00d3..1d2d91f 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java
@@ -2,9 +2,11 @@ package cy.agorise.crystalwallet.activities;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
@@ -52,6 +54,14 @@ public class IntroActivity extends CustomActivity {
@BindView(R.id.btnImportAccount)
public Button btnImportAccount;
+ /*
+ * For the window animation
+ * */
+ private MediaPlayer mediaPlayer;
+
+
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -64,7 +74,7 @@ public class IntroActivity extends CustomActivity {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//Log.d(TAG,"surfaceCreated");
- MediaPlayer mediaPlayer = MediaPlayer.create(IntroActivity.this, R.raw.appbar_background);
+ mediaPlayer = MediaPlayer.create(IntroActivity.this, R.raw.appbar_background);
mediaPlayer.setDisplay(mSurfaceView.getHolder());
mediaPlayer.setLooping(true);
mediaPlayer.start();
@@ -146,6 +156,17 @@ public class IntroActivity extends CustomActivity {
startActivity(intent);
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ //Release the media player
+ if(mediaPlayer!=null){
+ mediaPlayer.release();
+ mediaPlayer = null;
+ }
+ }
+
@OnClick(R.id.btnImportAccount)
public void importAccount() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/PatternRequestActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/PatternRequestActivity.java
index 0ecb4f8..b4334dd 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/activities/PatternRequestActivity.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/activities/PatternRequestActivity.java
@@ -71,7 +71,8 @@ public class PatternRequestActivity extends AppCompatActivity {
public void onComplete(List pattern) {
if (PasswordManager.checkPassword(patternEncrypted,patternToString(pattern))){
if (CrystalSecurityMonitor.getInstance(null).is2ndFactorSet()) {
- CrystalSecurityMonitor.getInstance(null).call2ndFactor(thisActivity);
+ //CrystalSecurityMonitor.getInstance(null).call2ndFactor(thisActivity);
+ thisActivity.finish();
} else {
thisActivity.finish();
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/SendTransactionActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/SendTransactionActivity.java
index f34db62..adfa17c 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/activities/SendTransactionActivity.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/activities/SendTransactionActivity.java
@@ -4,6 +4,7 @@ import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.widget.Button;
@@ -62,6 +63,9 @@ public class SendTransactionActivity extends AppCompatActivity implements UIVali
//@BindView(R.id.btnCancel)
Button btnCancel;
+ @BindView(R.id.fabCloseCamera)
+ FloatingActionButton btnCloseCamera;
+
private long cryptoNetAccountId;
private CryptoNetAccount cryptoNetAccount;
private GrapheneAccount grapheneAccount;
@@ -146,6 +150,15 @@ public class SendTransactionActivity extends AppCompatActivity implements UIVali
this.finish();
}
+
+
+ @OnClick(R.id.fabCloseCamera)
+ public void onClicCloseCamera(){
+
+
+ }
+
+
//@OnClick(R.id.btnSend)
public void importSend(){
if (this.sendTransactionValidator.isValid()) {
diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/SettingsActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/SettingsActivity.java
index a953b05..a17931c 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/activities/SettingsActivity.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/activities/SettingsActivity.java
@@ -50,6 +50,14 @@ public class SettingsActivity extends AppCompatActivity{
private SecuritySettingsFragment securitySettingsFragment;
+ /*
+ * For the window animation
+ * */
+ private MediaPlayer mediaPlayer;
+
+
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -64,7 +72,7 @@ public class SettingsActivity extends AppCompatActivity{
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//Log.d(TAG,"surfaceCreated");
- MediaPlayer mediaPlayer = MediaPlayer.create(SettingsActivity.this, R.raw.appbar_background);
+ mediaPlayer = MediaPlayer.create(SettingsActivity.this, R.raw.appbar_background);
mediaPlayer.setDisplay(mSurfaceView.getHolder());
mediaPlayer.setLooping(true);
mediaPlayer.start();
@@ -123,6 +131,17 @@ public class SettingsActivity extends AppCompatActivity{
}
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ //Release the media player
+ if(mediaPlayer != null){
+ mediaPlayer.release();
+ mediaPlayer = null;
+ }
+ }
+
@OnClick(R.id.ivGoBack)
public void goBack(){
onBackPressed();
diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java
index 54fe88e..7a5505f 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java
@@ -1,47 +1,74 @@
package cy.agorise.crystalwallet.apigenerator;
-import android.content.Context;
-
import java.util.HashMap;
+import cy.agorise.crystalwallet.apigenerator.insightapi.AddressesActivityWatcher;
import cy.agorise.crystalwallet.apigenerator.insightapi.BroadcastTransaction;
import cy.agorise.crystalwallet.apigenerator.insightapi.GetEstimateFee;
import cy.agorise.crystalwallet.apigenerator.insightapi.GetTransactionByAddress;
-import cy.agorise.crystalwallet.apigenerator.insightapi.GetTransactionData;
-import cy.agorise.crystalwallet.enums.CryptoNet;
+import cy.agorise.crystalwallet.enums.CryptoCoin;
import cy.agorise.crystalwallet.network.CryptoNetManager;
public class InsightApiGenerator {
- private static HashMap broadcaster = new HashMap();
- private static HashMap transactionGetters = new HashMap();
- private static HashMap transacitonFollowers = new HashMap();
+ private static HashMap transactionGetters = new HashMap();
+ private static HashMap transactionFollowers = new HashMap();
- public static void getTransactionFromAddress(CryptoNet cryptoNet, String address,
- ApiRequest request, Context context,
- boolean subscribe){
- if(!transactionGetters.containsKey(cryptoNet)){
- //TODO change this line
- transactionGetters.put(cryptoNet,new GetTransactionByAddress(null,CryptoNetManager.getURL(cryptoNet),context));
+ /**
+ * Fecth all the transaciton for a giving address
+ * @param cryptoCoin the crypto net of the address
+ * @param address The address String
+ * @param request the request api to response
+ * @param subscribe If needs to follow the address (Real time)
+ */
+ public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address,
+ ApiRequest request, boolean subscribe){
+ if(!transactionGetters.containsKey(cryptoCoin)){
+ transactionGetters.put(cryptoCoin,new GetTransactionByAddress(cryptoCoin,CryptoNetManager.getURL(cryptoCoin.getCryptoNet())));
}
-
- }
-
- public static void followTransaction(CryptoNet cryptoNet, String txid, Context context){
-
- }
-
- public static void broadcastTransaction(CryptoNet cryptoNet, String rawtx, ApiRequest request){
- if(!broadcaster.containsKey(cryptoNet)){
- //TODO change to multiple broadcast
- broadcaster.put(cryptoNet,new BroadcastTransaction(rawtx,null,
- CryptoNetManager.getURL(cryptoNet),null));
- broadcaster.get(cryptoNet).start();
+ transactionGetters.get(cryptoCoin).addAddress(address);
+ transactionGetters.get(cryptoCoin).start();
+ if(subscribe){
+ if(!transactionFollowers.containsKey(cryptoCoin)){
+ transactionFollowers.put(cryptoCoin,new AddressesActivityWatcher(CryptoNetManager.getURL(cryptoCoin.getCryptoNet()),cryptoCoin));
+ }
+ transactionFollowers.get(cryptoCoin).addAddress(address);
+ transactionFollowers.get(cryptoCoin).connect();
}
}
- public static void getEstimateFee(CryptoNet cryptoNet, final ApiRequest request){
- GetEstimateFee.getEstimateFee(CryptoNetManager.getURL(cryptoNet), new GetEstimateFee.estimateFeeListener() {
+ /**
+ * Broadcast an insight api transaction
+ * @param cryptoCoin The cryptoNet of the transaction
+ * @param rawtx the transaction to be broadcasted
+ */
+ public static void broadcastTransaction(CryptoCoin cryptoCoin, String rawtx, final ApiRequest request){
+ BroadcastTransaction bTransaction = new BroadcastTransaction(rawtx,
+ CryptoNetManager.getURL(cryptoCoin.getCryptoNet()), "api", new BroadcastTransaction.BroadCastTransactionListener() {
+ @Override
+ public void onSuccess() {
+ request.getListener().success(true,request.getId());
+ }
+
+ @Override
+ public void onFailure(String msg) {
+ request.getListener().fail(request.getId());
+ }
+
+ @Override
+ public void onConnecitonFailure() {
+ request.getListener().fail(request.getId());
+ }
+ });
+ bTransaction.start();
+ }
+
+ /**
+ * Fetch the estimated fee for a transaction
+ */
+ public static void getEstimateFee(CryptoCoin cryptoCoin, final ApiRequest request){
+ GetEstimateFee.getEstimateFee(CryptoNetManager.getURL(cryptoCoin.getCryptoNet()),
+ new GetEstimateFee.estimateFeeListener() {
@Override
public void estimateFee(long value) {
request.listener.success(value,request.getId());
diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/AccountActivityWatcher.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/AddressesActivityWatcher.java
similarity index 79%
rename from app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/AccountActivityWatcher.java
rename to app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/AddressesActivityWatcher.java
index 1745efb..719c412 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/AccountActivityWatcher.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/AddressesActivityWatcher.java
@@ -12,6 +12,7 @@ import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
+import cy.agorise.crystalwallet.enums.CryptoCoin;
import cy.agorise.crystalwallet.models.GeneralCoinAccount;
import io.socket.client.IO;
import io.socket.client.Socket;
@@ -24,12 +25,9 @@ import io.socket.emitter.Emitter;
*
*/
-public class AccountActivityWatcher {
+public class AddressesActivityWatcher {
- /**
- * The mAccount to be monitor
- */
- private final GeneralCoinAccount mAccount;
+ private final CryptoCoin cryptoCoin;
/**
* The list of address to monitor
*/
@@ -38,10 +36,6 @@ public class AccountActivityWatcher {
* the Socket.IO
*/
private Socket mSocket;
- /**
- * This app mContext, used to save on the DB
- */
- private final Context mContext;
private final String mServerUrl;
@@ -55,9 +49,9 @@ public class AccountActivityWatcher {
try {
System.out.println("Receive accountActivtyWatcher " + os[0].toString() );
String txid = ((JSONObject) os[0]).getString(InsightApiConstants.sTxTag);
- new GetTransactionData(txid, mAccount, mServerUrl, mContext).start();
+ new GetTransactionData(txid, mServerUrl, cryptoCoin).start();
} catch (JSONException ex) {
- Logger.getLogger(AccountActivityWatcher.class.getName()).log(Level.SEVERE, null, ex);
+ Logger.getLogger(AddressesActivityWatcher.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
@@ -84,7 +78,9 @@ public class AccountActivityWatcher {
private final Emitter.Listener onDisconnect = new Emitter.Listener() {
@Override
public void call(Object... os) {
- System.out.println("Disconnected to accountActivityWatcher");
+ try {
+ Thread.sleep(60000);
+ } catch (InterruptedException ignore) {}
mSocket.connect();
}
};
@@ -99,19 +95,20 @@ public class AccountActivityWatcher {
for(Object ob : os) {
System.out.println("accountActivityWatcher " + ob.toString());
}
+ try {
+ Thread.sleep(60000);
+ } catch (InterruptedException ignore) {}
+ mSocket.connect();
}
};
/**
* Basic constructor
*
- * @param mAccount The mAccount to be monitor
- * @param mContext This app mContext
*/
- public AccountActivityWatcher(String serverUrl, GeneralCoinAccount mAccount, Context mContext) {
+ public AddressesActivityWatcher(String serverUrl, CryptoCoin cryptoCoin) {
this.mServerUrl = serverUrl;
- this.mAccount = mAccount;
- this.mContext = mContext;
+ this.cryptoCoin = cryptoCoin;
try {
this.mSocket = IO.socket(serverUrl);
this.mSocket.on(Socket.EVENT_CONNECT, onConnect);
@@ -141,13 +138,11 @@ public class AccountActivityWatcher {
* Connects the Socket
*/
public void connect() {
- //TODO change to use log
- System.out.println("accountActivityWatcher connecting");
try{
- this.mSocket.connect();
- }catch(Exception e){
- //TODO change exception handler
- System.out.println("accountActivityWatcher exception " + e.getMessage());
+ if(this.mSocket == null || !this.mSocket.connected()) {
+ this.mSocket.connect();
+ }
+ }catch(Exception ignore){
}
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/BroadcastTransaction.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/BroadcastTransaction.java
index 1736b6a..c4fa9cc 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/BroadcastTransaction.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/BroadcastTransaction.java
@@ -22,29 +22,21 @@ public class BroadcastTransaction extends Thread implements Callback {
* The serviceGenerator to call
*/
private InsightApiServiceGenerator mServiceGenerator;
- /**
- * This app context, used to save on the DB
- */
- private Context mContext;
- /**
- * The account who sign the transaction
- */
- private GeneralCoinAccount mAccount;
- private String serverUrl;
+ private String mPath;
+
+ private BroadCastTransactionListener listener;
/**
* Basic Consturctor
* @param RawTx The RawTX in Hex String
- * @param account The account who signs the transaction
- * @param context This app context
+ *
*/
- public BroadcastTransaction(String RawTx, GeneralCoinAccount account, String serverUrl, Context context){
- this.serverUrl = serverUrl;
+ public BroadcastTransaction(String RawTx, String serverUrl, String path, BroadCastTransactionListener listener){
this.mServiceGenerator = new InsightApiServiceGenerator(serverUrl);
- this.mContext = context;
this.mRawTx = RawTx;
- this.mAccount = account;
+ this.listener = listener;
+ this.mPath = path;
}
/**
@@ -54,13 +46,9 @@ public class BroadcastTransaction extends Thread implements Callback {
@Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
- //TODO invalidated send
- //TODO call getTransactionData
- GetTransactionData trData = new GetTransactionData(response.body().txid,this.mAccount, this.serverUrl, this.mContext);
- trData.start();
+ listener.onSuccess();
} else {
- System.out.println("SENDTEST: not succesful " + response.message());
- //TODO change how to handle invalid transaction
+ listener.onFailure(response.message());
}
}
@@ -69,8 +57,7 @@ public class BroadcastTransaction extends Thread implements Callback {
*/
@Override
public void onFailure(Call call, Throwable t) {
- //TODO change how to handle invalid transaction
- System.out.println("SENDTEST: sendError " + t.getMessage() );
+ listener.onConnecitonFailure();
}
/**
@@ -79,7 +66,13 @@ public class BroadcastTransaction extends Thread implements Callback {
@Override
public void run() {
InsightApiService service = this.mServiceGenerator.getService(InsightApiService.class);
- Call broadcastTransaction = service.broadcastTransaction(InsightApiConstants.getPath(this.mAccount.getCryptoCoin()),this.mRawTx);
+ Call broadcastTransaction = service.broadcastTransaction(this.mPath,this.mRawTx);
broadcastTransaction.enqueue(this);
}
+
+ public interface BroadCastTransactionListener{
+ void onSuccess();
+ void onFailure(String msg);
+ void onConnecitonFailure();
+ }
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionByAddress.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionByAddress.java
index 8d92b39..5ca3894 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionByAddress.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionByAddress.java
@@ -3,14 +3,21 @@ package cy.agorise.crystalwallet.apigenerator.insightapi;
import android.content.Context;
import android.util.Log;
+import com.idescout.sql.SqlScoutServer;
+
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import cy.agorise.crystalwallet.apigenerator.InsightApiGenerator;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.AddressTxi;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Txi;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout;
+import cy.agorise.crystalwallet.enums.CryptoCoin;
+import cy.agorise.crystalwallet.enums.CryptoNet;
+import cy.agorise.crystalwallet.manager.GeneralAccountManager;
+import cy.agorise.crystalwallet.models.CryptoCurrency;
import cy.agorise.crystalwallet.models.GTxIO;
import cy.agorise.crystalwallet.models.GeneralCoinAccount;
import cy.agorise.crystalwallet.models.GeneralCoinAddress;
@@ -25,43 +32,34 @@ import retrofit2.Response;
*/
public class GetTransactionByAddress extends Thread implements Callback {
- /**
- * The account to be query
- */
- private GeneralCoinAccount mAccount;
/**
* The list of address to query
*/
- private List mAddresses = new ArrayList<>();
+ private List mAddresses = new ArrayList<>();
/**
* The serviceGenerator to call
*/
private InsightApiServiceGenerator mServiceGenerator;
- /**
- * This app context, used to save on the DB
- */
- private Context mContext;
private String serverUrl;
+ private CryptoCoin cryptoNet;
+ private boolean inProcess = false;
/**
* Basic consturcotr
- * @param account The account to be query
- * @param context This app context
*/
- public GetTransactionByAddress(GeneralCoinAccount account, String serverUrl, Context context) {
+ public GetTransactionByAddress(CryptoCoin cryptoNet, String serverUrl) {
+ this.cryptoNet = cryptoNet;
this.serverUrl = serverUrl;
- this.mAccount = account;
this.mServiceGenerator = new InsightApiServiceGenerator(serverUrl);
- this.mContext = context;
}
/**
* add an address to be query
* @param address the address to be query
*/
- public void addAddress(GeneralCoinAddress address) {
+ public void addAddress(String address) {
this.mAddresses.add(address);
}
@@ -73,110 +71,15 @@ public class GetTransactionByAddress extends Thread implements Callback call, Response response) {
+ inProcess = false;
if (response.isSuccessful()) {
boolean changed = false;
AddressTxi addressTxi = response.body();
for (Txi txi : addressTxi.items) {
- GeneralCoinAccount tempAccount = null;
- GeneralTransaction transaction = new GeneralTransaction();
- transaction.setAccount(this.mAccount);
- transaction.setTxid(txi.txid);
- transaction.setBlock(txi.blockheight);
- transaction.setDate(new Date(txi.time * 1000));
- transaction.setFee((long) (txi.fee * Math.pow(10,this.mAccount.getCryptoCoin().getPrecision())));
- transaction.setConfirm(txi.confirmations);
- transaction.setType(this.mAccount.getCryptoCoin());
- transaction.setBlockHeight(txi.blockheight);
-
- for (Vin vin : txi.vin) {
- GTxIO input = new GTxIO();
- input.setAmount((long) (vin.value * Math.pow(10,this.mAccount.getCryptoCoin().getPrecision())));
- input.setTransaction(transaction);
- input.setOut(true);
- input.setType(this.mAccount.getCryptoCoin());
- String addr = vin.addr;
- input.setAddressString(addr);
- input.setIndex(vin.n);
- input.setScriptHex(vin.scriptSig.hex);
- input.setOriginalTxid(vin.txid);
- for (GeneralCoinAddress address : this.mAddresses) {
- if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) {
- input.setAddress(address);
- tempAccount = address.getAccount();
-
- if (!address.hasTransactionOutput(input, this.mAccount.getNetworkParam())) {
- address.getTransactionOutput().add(input);
- }
- changed = true;
- }
- }
- transaction.getTxInputs().add(input);
- }
-
- for (Vout vout : txi.vout) {
- if(vout.scriptPubKey.addresses == null || vout.scriptPubKey.addresses.length <= 0){
- // The address is null, this must be a memo
- String hex = vout.scriptPubKey.hex;
- int opReturnIndex = hex.indexOf("6a");
- if(opReturnIndex >= 0) {
- byte[] memoBytes = new byte[Integer.parseInt(hex.substring(opReturnIndex+2,opReturnIndex+4),16)];
- for(int i = 0; i < memoBytes.length;i++){
- memoBytes[i] = Byte.parseByte(hex.substring(opReturnIndex+4+(i*2),opReturnIndex+6+(i*2)),16);
- }
- transaction.setMemo(new String(memoBytes));
- }
- }else {
- GTxIO output = new GTxIO();
- output.setAmount((long) (vout.value * Math.pow(10, this.mAccount.getCryptoCoin().getPrecision())));
- output.setTransaction(transaction);
- output.setOut(false);
- output.setType(this.mAccount.getCryptoCoin());
- String addr = vout.scriptPubKey.addresses[0];
- output.setAddressString(addr);
- output.setIndex(vout.n);
- output.setScriptHex(vout.scriptPubKey.hex);
- for (GeneralCoinAddress address : this.mAddresses) {
- if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) {
- output.setAddress(address);
- tempAccount = address.getAccount();
-
- if (!address.hasTransactionInput(output, this.mAccount.getNetworkParam())) {
- address.getTransactionInput().add(output);
- }
- changed = true;
- }
- }
-
- transaction.getTxOutputs().add(output);
- }
- }
- if(txi.txlock && txi.confirmations< this.mAccount.getCryptoNet().getConfirmationsNeeded()){
- transaction.setConfirm(this.mAccount.getCryptoNet().getConfirmationsNeeded());
- }
- //TODO database
- /*SCWallDatabase db = new SCWallDatabase(this.mContext);
- long idTransaction = db.getGeneralTransactionId(transaction);
- if (idTransaction == -1) {
- db.putGeneralTransaction(transaction);
- } else {
- transaction.setId(idTransaction);
- db.updateGeneralTransaction(transaction);
- }*/
-
- if (tempAccount != null && transaction.getConfirm() < this.mAccount.getCryptoNet().getConfirmationsNeeded()) {
- new GetTransactionData(transaction.getTxid(), tempAccount, this.serverUrl, this.mContext, true).start();
- }
- for (GeneralCoinAddress address : this.mAddresses) {
- if (address.updateTransaction(transaction)) {
- break;
- }
- }
+ GeneralAccountManager.getAccountManager(this.cryptoNet).processTxi(txi);
}
- if(changed) {
- this.mAccount.balanceChange();
- }
}
}
@@ -187,6 +90,7 @@ public class GetTransactionByAddress extends Thread implements Callback call, Throwable t) {
+ inProcess = false;
Log.e("GetTransactionByAddress", "Error in json format");
}
@@ -195,14 +99,15 @@ public class GetTransactionByAddress extends Thread implements Callback 0) {
+ if (this.mAddresses.size() > 0 && !inProcess) {
+ inProcess = true;
StringBuilder addressToQuery = new StringBuilder();
- for (GeneralCoinAddress address : this.mAddresses) {
- addressToQuery.append(address.getAddressString(this.mAccount.getNetworkParam())).append(",");
+ for (String address : this.mAddresses) {
+ addressToQuery.append(address).append(",");
}
addressToQuery.deleteCharAt(addressToQuery.length() - 1);
InsightApiService service = this.mServiceGenerator.getService(InsightApiService.class);
- Call addressTxiCall = service.getTransactionByAddress(InsightApiConstants.getPath(this.mAccount.getCryptoCoin()),addressToQuery.toString());
+ Call addressTxiCall = service.getTransactionByAddress(this.serverUrl,addressToQuery.toString());
addressTxiCall.enqueue(this);
}
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionData.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionData.java
index d50d5dc..2286c0b 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionData.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionData.java
@@ -7,6 +7,8 @@ import java.util.Date;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Txi;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout;
+import cy.agorise.crystalwallet.enums.CryptoCoin;
+import cy.agorise.crystalwallet.manager.GeneralAccountManager;
import cy.agorise.crystalwallet.models.GTxIO;
import cy.agorise.crystalwallet.models.GeneralCoinAccount;
import cy.agorise.crystalwallet.models.GeneralCoinAddress;
@@ -20,10 +22,6 @@ import retrofit2.Response;
*/
public class GetTransactionData extends Thread implements Callback {
- /**
- * The account to be query
- */
- private final GeneralCoinAccount mAccount;
/**
* The transaction txid to be query
*/
@@ -32,10 +30,6 @@ public class GetTransactionData extends Thread implements Callback {
* The serviceGenerator to call
*/
private InsightApiServiceGenerator mServiceGenerator;
- /**
- * This app context, used to save on the DB
- */
- private Context mContext;
private String mServerUrl;
/**
@@ -43,30 +37,28 @@ public class GetTransactionData extends Thread implements Callback {
*/
private boolean mMustWait = false;
+ private CryptoCoin cryptoCoin;
+
/**
* Constructor used to query for a transaction with unknown confirmations
* @param txid The txid of the transaciton to be query
- * @param account The account to be query
- * @param context This app Context
*/
- public GetTransactionData(String txid, GeneralCoinAccount account,String serverUrl, Context context) {
- this(txid, account, serverUrl, context, false);
+ public GetTransactionData(String txid, String serverUrl, CryptoCoin cryptoCoin) {
+ this(txid, serverUrl, cryptoCoin, false);
+
}
/**
* Consturctor to be used qhen the confirmations of the transaction are known
* @param txid The txid of the transaciton to be query
- * @param account The account to be query
- * @param context This app Context
* @param mustWait If there is less confirmation that needed
*/
- public GetTransactionData(String txid, GeneralCoinAccount account,String serverUrl, Context context, boolean mustWait) {
+ public GetTransactionData(String txid, String serverUrl, CryptoCoin cryptoCoin, boolean mustWait) {
this.mServerUrl = serverUrl;
- this.mAccount = account;
this.mTxId= txid;
this.mServiceGenerator = new InsightApiServiceGenerator(serverUrl);
- this.mContext = context;
this.mMustWait = mustWait;
+ this.cryptoCoin = cryptoCoin;
}
/**
@@ -84,104 +76,19 @@ public class GetTransactionData extends Thread implements Callback {
}
InsightApiService service = this.mServiceGenerator.getService(InsightApiService.class);
- Call txiCall = service.getTransaction(InsightApiConstants.getPath(this.mAccount.getCryptoCoin()),this.mTxId);
+ Call txiCall = service.getTransaction(this.mServerUrl,this.mTxId);
txiCall.enqueue(this);
}
@Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
+
Txi txi = response.body();
-
- GeneralTransaction transaction = new GeneralTransaction();
- transaction.setAccount(this.mAccount);
- transaction.setTxid(txi.txid);
- transaction.setBlock(txi.blockheight);
- transaction.setDate(new Date(txi.time * 1000));
- transaction.setFee((long) (txi.fee * Math.pow(10,this.mAccount.getCryptoCoin().getPrecision())));
- transaction.setConfirm(txi.confirmations);
- transaction.setType(this.mAccount.getCryptoCoin());
- transaction.setBlockHeight(txi.blockheight);
-
- for (Vin vin : txi.vin) {
- GTxIO input = new GTxIO();
- input.setAmount((long) (vin.value * Math.pow(10,this.mAccount.getCryptoCoin().getPrecision())));
- input.setTransaction(transaction);
- input.setOut(true);
- input.setType(this.mAccount.getCryptoCoin());
- String addr = vin.addr;
- input.setAddressString(addr);
- input.setIndex(vin.n);
- input.setScriptHex(vin.scriptSig.hex);
- input.setOriginalTxid(vin.txid);
- for (GeneralCoinAddress address : this.mAccount.getAddresses()) {
- if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) {
- input.setAddress(address);
- if (!address.hasTransactionOutput(input, this.mAccount.getNetworkParam())) {
- address.getTransactionOutput().add(input);
- }
- }
- }
- transaction.getTxInputs().add(input);
- }
-
- for (Vout vout : txi.vout) {
- if(vout.scriptPubKey.addresses == null || vout.scriptPubKey.addresses.length <= 0){
- // The address is null, this must be a memo
- String hex = vout.scriptPubKey.hex;
- int opReturnIndex = hex.indexOf("6a");
- if(opReturnIndex >= 0) {
- byte[] memoBytes = new byte[Integer.parseInt(hex.substring(opReturnIndex+2,opReturnIndex+4),16)];
- for(int i = 0; i < memoBytes.length;i++){
- memoBytes[i] = Byte.parseByte(hex.substring(opReturnIndex+4+(i*2),opReturnIndex+6+(i*2)),16);
- }
- transaction.setMemo(new String(memoBytes));
- System.out.println("Memo read : " + transaction.getMemo()); //TODO log this line
- }
-
- }else {
- GTxIO output = new GTxIO();
- output.setAmount((long) (vout.value * Math.pow(10, this.mAccount.getCryptoCoin().getPrecision())));
- output.setTransaction(transaction);
- output.setOut(false);
- output.setType(this.mAccount.getCryptoCoin());
- String addr = vout.scriptPubKey.addresses[0];
- output.setAddressString(addr);
- output.setIndex(vout.n);
- output.setScriptHex(vout.scriptPubKey.hex);
- for (GeneralCoinAddress address : this.mAccount.getAddresses()) {
- if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) {
- output.setAddress(address);
- if (!address.hasTransactionInput(output, this.mAccount.getNetworkParam())) {
- address.getTransactionInput().add(output);
- }
- }
- }
- transaction.getTxOutputs().add(output);
- }
- }
-
- // This is for features like dash instantSend
- if(txi.txlock && txi.confirmations< this.mAccount.getCryptoNet().getConfirmationsNeeded()){
- transaction.setConfirm(this.mAccount.getCryptoNet().getConfirmationsNeeded());
- }
-
- //TODO database
- /*SCWallDatabase db = new SCWallDatabase(this.mContext);
- long idTransaction = db.getGeneralTransactionId(transaction);
- if (idTransaction == -1) {
- db.putGeneralTransaction(transaction);
- } else {
- transaction.setId(idTransaction);
- db.updateGeneralTransaction(transaction);
- }*/
-
- this.mAccount.updateTransaction(transaction);
- this.mAccount.balanceChange();
-
- if (transaction.getConfirm() < this.mAccount.getCryptoNet().getConfirmationsNeeded()) {
+ GeneralAccountManager.getAccountManager(this.cryptoCoin).processTxi(txi);
+ if (txi.confirmations < this.cryptoCoin.getCryptoNet().getConfirmationsNeeded()) {
//If transaction weren't confirmed, add the transaction to watch for change on the confirmations
- new GetTransactionData(this.mTxId, this.mAccount, this.mServerUrl, this.mContext, true).start();
+ new GetTransactionData(this.mTxId, this.mServerUrl, this.cryptoCoin, true).start();
}
}
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinTransactionDao.java b/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinTransactionDao.java
new file mode 100644
index 0000000..5b62286
--- /dev/null
+++ b/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinTransactionDao.java
@@ -0,0 +1,26 @@
+package cy.agorise.crystalwallet.dao;
+
+import android.arch.lifecycle.LiveData;
+import android.arch.persistence.room.Dao;
+import android.arch.persistence.room.Insert;
+import android.arch.persistence.room.OnConflictStrategy;
+import android.arch.persistence.room.Query;
+
+import cy.agorise.crystalwallet.models.BitcoinTransaction;
+import cy.agorise.crystalwallet.models.BitcoinTransactionExtended;
+
+/**
+ * Created by Henry Varona on 10/02/2018.
+ */
+@Dao
+public interface BitcoinTransactionDao {
+
+ @Query("SELECT * FROM crypto_coin_transaction cct, bitcoin_transaction bt WHERE bt.crypto_coin_transaction_id = cct.id")
+ LiveData getAll();
+
+ @Query("SELECT * FROM bitcoin_transaction bt WHERE bt.tx_id = :txid")
+ BitcoinTransaction getByTxid(String txid);
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ public long[] insertBitcoinTransaction(BitcoinTransaction... transactions);
+}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/dao/CrystalDatabase.java b/app/src/main/java/cy/agorise/crystalwallet/dao/CrystalDatabase.java
index cd8840a..7dc40c0 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/dao/CrystalDatabase.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/dao/CrystalDatabase.java
@@ -10,6 +10,8 @@ import android.content.Context;
import cy.agorise.crystalwallet.dao.converters.Converters;
import cy.agorise.crystalwallet.models.AccountSeed;
+import cy.agorise.crystalwallet.models.BitcoinTransaction;
+import cy.agorise.crystalwallet.models.BitcoinTransactionGTxIO;
import cy.agorise.crystalwallet.models.BitsharesAccountNameCache;
import cy.agorise.crystalwallet.models.BitsharesAssetInfo;
import cy.agorise.crystalwallet.models.Contact;
@@ -39,8 +41,10 @@ import cy.agorise.crystalwallet.models.GrapheneAccountInfo;
BitsharesAssetInfo.class,
BitsharesAccountNameCache.class,
CryptoCurrencyEquivalence.class,
- GeneralSetting.class
-}, version = 4, exportSchema = false)
+ GeneralSetting.class,
+ BitcoinTransaction.class,
+ BitcoinTransactionGTxIO.class
+}, version = 5, exportSchema = false)
@TypeConverters({Converters.class})
public abstract class CrystalDatabase extends RoomDatabase {
@@ -57,6 +61,7 @@ public abstract class CrystalDatabase extends RoomDatabase {
public abstract BitsharesAccountNameCacheDao bitsharesAccountNameCacheDao();
public abstract CryptoCurrencyEquivalenceDao cryptoCurrencyEquivalenceDao();
public abstract GeneralSettingDao generalSettingDao();
+ public abstract BitcoinTransactionDao bitcoinTransactionDao();
public static CrystalDatabase getAppDatabase(Context context) {
if (instance == null) {
@@ -66,6 +71,7 @@ public abstract class CrystalDatabase extends RoomDatabase {
.allowMainThreadQueries()
.addMigrations(MIGRATION_2_3)
.addMigrations(MIGRATION_3_4)
+ .addMigrations(MIGRATION_4_5)
.build();
}
return instance;
@@ -91,4 +97,25 @@ public abstract class CrystalDatabase extends RoomDatabase {
}
};
+
+ static final Migration MIGRATION_4_5 = new Migration(4, 5) {
+ @Override
+ public void migrate(SupportSQLiteDatabase database) {
+ database.execSQL("CREATE TABLE bitcoin_transaction ("
+ +"crypto_coin_transaction_id INTEGER PRIMARY KEY NOT NULL,"
+ +"tx_id TEXT NOT NULL,"
+ +"block INTEGER NOT NULL,"
+ +"fee INTEGER NOT NULL,"
+ +"confirmations INTEGER NOT NULL,"
+ +"FOREIGN KEY (crypto_coin_transaction_id) REFERENCES crypto_coin_transaction(id) ON DELETE CASCADE)");
+
+ database.execSQL("CREATE TABLE bitcoin_transaction_gt_io ("
+ +"bitcoin_transaction_id INTEGER NOT NULL,"
+ +"io_index INTEGER NOT NULL,"
+ +"address TEXT,"
+ +"is_output INTEGER NOT NULL,"
+ +"PRIMARY KEY (bitcoin_transaction_id, io_index, is_output),"
+ +"FOREIGN KEY (bitcoin_transaction_id) REFERENCES bitcoin_transaction(crypto_coin_transaction_id) ON DELETE CASCADE)");
+ }
+ };
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/BalanceFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/BalanceFragment.java
index c696b49..8522f47 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/fragments/BalanceFragment.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/BalanceFragment.java
@@ -71,7 +71,7 @@ public class BalanceFragment extends Fragment {
vCryptoNetBalanceListView.setData(cryptoNetBalances, fragment);
final int size = cryptoNetBalances.size();
- if(size==1){
+ if(size==0){
tvNobalances.setVisibility(View.VISIBLE);
}
else{
diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/GeneralCryptoNetAccountSettingsFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/GeneralCryptoNetAccountSettingsFragment.java
index 2c182a9..d51e3e5 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/fragments/GeneralCryptoNetAccountSettingsFragment.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/GeneralCryptoNetAccountSettingsFragment.java
@@ -1,6 +1,10 @@
package cy.agorise.crystalwallet.fragments;
+import android.app.Activity;
import android.arch.lifecycle.LiveData;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
@@ -8,11 +12,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
+import android.widget.Toast;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
+import butterknife.OnClick;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.models.AccountSeed;
@@ -30,9 +36,15 @@ public class GeneralCryptoNetAccountSettingsFragment extends Fragment {
@BindView(R.id.tvMnemonic)
TextView tvMnemonic;
+ @BindView(R.id.btnCopy)
+ Button btnCopy;
+
CryptoNetAccount cryptoNetAccount;
AccountSeed accountSeed;
+
+
+
public GeneralCryptoNetAccountSettingsFragment() {
if (getArguments() != null) {
@@ -83,4 +95,24 @@ public class GeneralCryptoNetAccountSettingsFragment extends Fragment {
tvMnemonic.setText(this.accountSeed.getMasterSeed());
}
}
+
+ /*
+ * Clic on button copy to clipboard
+ * */
+ @OnClick(R.id.btnCopy)
+ public void btnCopyClick(){
+
+ /*
+ * Save to clipboard the brainkey chain
+ * */
+ final Activity activity = getActivity();
+ ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText(tvMnemonic.getText(), tvMnemonic.getText().toString());
+ clipboard.setPrimaryClip(clip);
+
+ /*
+ * Success message
+ * */
+ Toast.makeText(activity,getResources().getString(R.string.window_seed_toast_clipboard), Toast.LENGTH_SHORT).show();
+ }
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/ImportAccountOptionsFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/ImportAccountOptionsFragment.java
index 4b1e38c..845cb9c 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/fragments/ImportAccountOptionsFragment.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/ImportAccountOptionsFragment.java
@@ -5,12 +5,17 @@ import android.app.Dialog;
import android.arch.lifecycle.ViewModelProviders;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -19,6 +24,8 @@ import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
+import com.vincent.filepicker.ToastUtil;
+
import java.net.URISyntaxException;
import butterknife.BindView;
@@ -50,6 +57,7 @@ public class ImportAccountOptionsFragment extends DialogFragment {
@BindView(R.id.btnImportBackup)
Button btnImportBackup;
+ private static final int PERMISSION_REQUEST_CODE = 1;
/*
Dialog for loading
@@ -110,18 +118,88 @@ public class ImportAccountOptionsFragment extends DialogFragment {
@OnClick (R.id.btnImportBackup)
public void importBackup(){
- Intent fileIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- fileIntent.setType("*/*");
- fileIntent.addCategory(Intent.CATEGORY_OPENABLE);
- startActivityForResult(fileIntent, FILE_CONTENT_REQUEST_CODE);
+ if (Build.VERSION.SDK_INT >= 23) {
+ if (checkPermission()) {
+
+ Intent fileIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ fileIntent.setType("*/*");
+ fileIntent.addCategory(Intent.CATEGORY_OPENABLE);
+ startActivityForResult(fileIntent, FILE_CONTENT_REQUEST_CODE);
+
+ } else {
+ requestPermission(); // Code for permission
+ }
+ }
+ else {
+
+ Intent fileIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ fileIntent.setType("*/*");
+ fileIntent.addCategory(Intent.CATEGORY_OPENABLE);
+ startActivityForResult(fileIntent, FILE_CONTENT_REQUEST_CODE);
+ }
}
@OnClick (R.id.btnImportSeed)
public void importSeed(){
- Intent intent = new Intent(this.getActivity(), ImportSeedActivity.class);
- startActivity(intent);
+
+ if (Build.VERSION.SDK_INT >= 23) {
+
+ if (checkPermission()) {
+
+ Intent intent = new Intent(this.getActivity(), ImportSeedActivity.class);
+ startActivity(intent);
+
+ } else {
+ requestPermission(); // Code for permission
+ }
+ }
+ else {
+ Intent intent = new Intent(this.getActivity(), ImportSeedActivity.class);
+ startActivity(intent);
+ }
+ }
+
+
+ private boolean checkPermission() {
+ int result = ContextCompat.checkSelfPermission(getActivity(), android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ if (result == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ private void requestPermission() {
+
+ Log.i("log", "requestPermission() entered");
+
+ if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ Toast.makeText(getActivity(), "Write External Storage permission allows us to do store images. Please allow this permission in App Settings.", Toast.LENGTH_LONG).show();
+ } else {
+ // ActivityCompat.requestPermissions(getActivity(), new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
+ requestPermissions(new String[] {android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
+ }
+ }
+
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+
+ switch (requestCode) {
+ case PERMISSION_REQUEST_CODE:
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+
+ Intent intent = new Intent(getActivity(), ImportSeedActivity.class);
+ startActivity(intent);
+
+ } else {
+ ToastUtil.getInstance(getActivity()).showToast(getActivity().getString(R.string.Permission_Denied_WRITE_EXTERNAL_STORAGE));
+ }
+ break;
+ }
}
@Override
diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java
index 3055135..56b6600 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java
@@ -8,11 +8,13 @@ import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.content.ContextWrapper;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
@@ -22,20 +24,20 @@ import android.support.v4.app.ActivityCompat;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
-import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
+import android.widget.Toast;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
@@ -56,6 +58,8 @@ import butterknife.OnClick;
import butterknife.OnItemSelected;
import butterknife.OnTextChanged;
import cy.agorise.crystalwallet.R;
+import cy.agorise.crystalwallet.dialogs.material.CrystalDialog;
+import cy.agorise.crystalwallet.dialogs.material.ToastIt;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestListener;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.requestmanagers.ValidateBitsharesSendRequest;
@@ -93,6 +97,8 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
View viewSend;
@BindView(R.id.tvToError)
TextView tvToError;
+ @BindView(R.id.fabCloseCamera)
+ FloatingActionButton btnCloseCamera;
@BindView(R.id.spAsset)
Spinner spAsset;
@BindView(R.id.tvAssetError)
@@ -122,6 +128,14 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
@BindView(R.id.gravatar)
CircularImageView userImg;
+ @BindView(R.id.viewCamera)
+ View viewCamera;
+
+ /*
+ * Flag to control when the camera is visible and when is hide
+ * */
+ private boolean cameraVisible = true;
+
Button btnScanQrCode;
private long cryptoNetAccountId;
@@ -131,7 +145,10 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
private FloatingActionButton fabSend;
private AlertDialog.Builder builder;
-
+ /*
+ Dialog for loading
+ */
+ private CrystalDialog crystalDialog;
public static SendTransactionFragment newInstance(long cryptoNetAccountId) {
SendTransactionFragment f = new SendTransactionFragment();
@@ -273,19 +290,123 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
}
loadUserImage();
- try {
- verifyCameraPermissions(getActivity());
- beginScanQrCode();
- }catch(Exception e){
- e.printStackTrace();
+
+ /*
+ * Check for CAMERA permission
+ * */
+ if (Build.VERSION.SDK_INT >= 23) {
+ if (checkPermission()) {
+ // Code for above or equal 23 API Oriented Device
+ // Your Permission granted already .Do next code
+
+ /*
+ * Init the camera
+ * */
+ try {
+ beginScanQrCode();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+
+ } else {
+ requestPermission(); // Code for permission
+ }
+ }
+ else {
+
+ // Code for Below 23 API Oriented Device
+ // Do next code
+
+ /*
+ * Init the camera
+ * */
+ try {
+ beginScanQrCode();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
}
return builder.setView(view).create();
}
+
+ private void requestPermission() {
+
+ if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.CAMERA)) {
+ Toast.makeText(getActivity(), getActivity().getString(R.string.permission_denied_camera), Toast.LENGTH_LONG).show();
+
+ /*
+ * Disable the button of the camera visibility
+ * */
+ disableVisibilityCamera();
+
+ } else {
+ requestPermissions(new String[] {android.Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
+ }
+ }
+
+ private void disableVisibilityCamera(){
+
+ /*
+ * Hide the button, the user can not modify the visibility
+ * */
+ btnCloseCamera.setVisibility(View.INVISIBLE);
+ }
+
+ private boolean checkPermission() {
+ int result = ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA);
+ if (result == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+
+ switch (requestCode) {
+ case REQUEST_CAMERA_PERMISSION:
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ Log.e("value", "Permission Granted, Now you can use camera .");
+
+ getActivity().runOnUiThread(new Runnable(){
+ public void run() {
+ Toast.makeText(getActivity(), getActivity().getString(R.string.permission_granted_camera), Toast.LENGTH_LONG).show();
+ }
+ });
+
+ /*
+ * Init the camera
+ * */
+ try {
+ beginScanQrCode();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+
+ } else {
+ Log.e("value", "Permission Denied, You cannot use the camera.");
+
+ getActivity().runOnUiThread(new Runnable(){
+ public void run() {
+ Toast.makeText(getActivity(), getActivity().getString(R.string.permission_denied_camera), Toast.LENGTH_LONG).show();
+ }
+ });
+ }
+ break;
+ }
+ }
+
@Override
public void onResume() {
super.onResume();
+ mScannerView.setResultHandler(this);
+ mScannerView.startCamera();
/*builder.setNeutralButton("Scan QR Code", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
@@ -300,6 +421,12 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
loadUserImage();
}
+ @Override
+ public void onPause() {
+ super.onPause();
+ mScannerView.stopCamera();
+ }
+
@Override
public void onDestroy() {
super.onDestroy();
@@ -351,6 +478,71 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
}
+ @OnClick(R.id.fabCloseCamera)
+ public void onClicCloseCamera(){
+ mScannerView.stopCamera();
+
+ /*
+ * Hide the camera or show it
+ * */
+ if(cameraVisible){
+ hideCamera();
+ }
+ else{
+ showCamera();
+ }
+ }
+
+ /*
+ * Show the camera and hide the black background
+ * */
+ private void showCamera(){
+
+ /*
+ * Change visibilities of views
+ * */
+ viewCamera.setVisibility(View.GONE);
+ mScannerView.setVisibility(View.VISIBLE);
+
+ /*
+ * Change icon
+ * */
+ btnCloseCamera.setImageDrawable(getResources().getDrawable(R.drawable.ic_close));
+
+ /*
+ * Reset variable
+ * */
+ cameraVisible = true;
+
+ /*
+ * Star the camera again
+ * */
+ beginScanQrCode();
+ }
+
+
+ /*
+ * Hide the camera and show the black background
+ * */
+ private void hideCamera(){
+
+ /*
+ * Change visibilities of views
+ * */
+ viewCamera.setVisibility(View.VISIBLE);
+ mScannerView.setVisibility(View.INVISIBLE);
+
+ /*
+ * Change icon
+ * */
+ btnCloseCamera.setImageDrawable(getResources().getDrawable(R.drawable.ok));
+
+ /*
+ * Reset variable
+ * */
+ cameraVisible = false;
+ }
+
@OnTextChanged(value = R.id.etMemo,
callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void afterMemoChanged(Editable editable) {
@@ -408,6 +600,8 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
@OnClick(R.id.btnSend)
public void sendTransaction(){
+ final SendTransactionFragment thisFragment = this;
+
if (this.sendTransactionValidator.isValid()) {
CryptoNetAccount fromAccountSelected = (CryptoNetAccount) spFrom.getItems().get(spFrom.getSelectedIndex());
@@ -439,13 +633,26 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
public void onCarryOut() {
if (sendRequest.getStatus().equals(ValidateBitsharesSendRequest.StatusCode.SUCCEEDED)){
try {
- this.finalize();
+ crystalDialog.dismiss();
+ thisFragment.dismiss();
+ //thisFragment.finalize();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
+ } else {
+ Toast.makeText(getContext(), getContext().getString(R.string.unable_to_send_amount), Toast.LENGTH_LONG);
}
}
});
+
+ /*
+ * Show loading dialog
+ * */
+ crystalDialog = new CrystalDialog((Activity) getContext());
+ crystalDialog.setText("Sending");
+ crystalDialog.progress();
+ crystalDialog.show();
+
CryptoNetInfoRequests.getInstance().addRequest(sendRequest);
}
}
@@ -453,6 +660,7 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
public void beginScanQrCode(){
//mScannerView = new ZXingScannerView(getContext());
mScannerView.setFormats(listOf(BarcodeFormat.QR_CODE));
+ mScannerView.setAspectTolerance(0.5f);
mScannerView.setAutoFocus(true);
mScannerView.setLaserColor(R.color.colorAccent);
mScannerView.setMaskColor(R.color.colorAccent);
@@ -467,20 +675,6 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
};
- public static void verifyCameraPermissions(Activity activity) {
- // Check if we have write permission
- int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
-
- if (permission != PackageManager.PERMISSION_GRANTED) {
- // We don't have permission so prompt the user
- ActivityCompat.requestPermissions(
- activity,
- PERMISSIONS_CAMERA,
- REQUEST_CAMERA_PERMISSION
- );
- }
- }
-
@Override
public void onValidationSucceeded(final ValidationField field) {
final SendTransactionFragment fragment = this;
@@ -534,7 +728,6 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat
@Override
public void handleResult(Result result) {
try {
- System.out.println("CAMERA result " + result.getText() );
Invoice invoice = Invoice.fromQrCode(result.getText());
etTo.setText(invoice.getTo());
diff --git a/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java b/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java
index a3871fb..ec5edb2 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java
@@ -2,6 +2,7 @@ package cy.agorise.crystalwallet.manager;
import android.annotation.SuppressLint;
import android.content.Context;
+import android.util.Log;
import com.google.common.primitives.UnsignedLong;
@@ -20,6 +21,7 @@ import cy.agorise.crystalwallet.apigenerator.GrapheneApiGenerator;
import cy.agorise.crystalwallet.apigenerator.grapheneoperation.AccountUpgradeOperationBuilder;
import cy.agorise.crystalwallet.application.constant.BitsharesConstant;
import cy.agorise.crystalwallet.dao.AccountSeedDao;
+import cy.agorise.crystalwallet.enums.CryptoCoin;
import cy.agorise.crystalwallet.models.BitsharesAccountNameCache;
import cy.agorise.crystalwallet.models.seed.BIP39;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetEquivalentRequest;
@@ -64,8 +66,6 @@ import cy.agorise.graphenej.operations.TransferOperationBuilder;
*/
public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener {
- //private final static String BITSHARES_TESTNET_CHAIN_ID= "9cf6f255a208100d2bb275a3c52f4b1589b7ec9c9bfc2cb2a5fe6411295106d8";
-
private final static String SIMPLE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
private final static String DEFAULT_TIME_ZONE = "GMT";
@@ -129,7 +129,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
long[] idAccount = db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount);
grapheneAccount.setId(idAccount[0]);
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount));
- subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
+ //subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
}
@Override
@@ -147,7 +147,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount);
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount));
- subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
+ //subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
}
@Override
@@ -159,7 +159,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount);
db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount));
- subscribeBitsharesAccount(grapheneAccount.getId(), grapheneAccount.getAccountId(), context);
+ //subscribeBitsharesAccount(grapheneAccount.getId(), grapheneAccount.getAccountId(), context);
}
}
}
@@ -221,24 +221,26 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI
*/
@Override
public void onNewRequest(CryptoNetInfoRequest request) {
- if (request instanceof ValidateImportBitsharesAccountRequest){
- this.validateImportAccount((ValidateImportBitsharesAccountRequest) request);
- } else if (request instanceof ValidateExistBitsharesAccountRequest){
- this.validateExistAcccount((ValidateExistBitsharesAccountRequest) request);
- } else if (request instanceof ValidateBitsharesSendRequest){
- this.validateSendRequest((ValidateBitsharesSendRequest) request);
- }else if (request instanceof CryptoNetEquivalentRequest){
- this.getEquivalentValue((CryptoNetEquivalentRequest) request);
- }else if (request instanceof ValidateCreateBitsharesAccountRequest){
- this.validateCreateAccount((ValidateCreateBitsharesAccountRequest) request);
- }else if (request instanceof ValidateBitsharesLTMUpgradeRequest){
- this.validateLTMAccountUpgrade((ValidateBitsharesLTMUpgradeRequest) request);
- }else if (request instanceof GetBitsharesAccountNameCacheRequest){
- this.getBitsharesAccountNameCacheRequest((GetBitsharesAccountNameCacheRequest) request);
- }else{
+ if(request.getCoin().equals(CryptoCoin.BITSHARES)) {
+ if (request instanceof ValidateImportBitsharesAccountRequest) {
+ this.validateImportAccount((ValidateImportBitsharesAccountRequest) request);
+ } else if (request instanceof ValidateExistBitsharesAccountRequest) {
+ this.validateExistAcccount((ValidateExistBitsharesAccountRequest) request);
+ } else if (request instanceof ValidateBitsharesSendRequest) {
+ this.validateSendRequest((ValidateBitsharesSendRequest) request);
+ } else if (request instanceof CryptoNetEquivalentRequest) {
+ this.getEquivalentValue((CryptoNetEquivalentRequest) request);
+ } else if (request instanceof ValidateCreateBitsharesAccountRequest) {
+ this.validateCreateAccount((ValidateCreateBitsharesAccountRequest) request);
+ } else if (request instanceof ValidateBitsharesLTMUpgradeRequest) {
+ this.validateLTMAccountUpgrade((ValidateBitsharesLTMUpgradeRequest) request);
+ } else if (request instanceof GetBitsharesAccountNameCacheRequest) {
+ this.getBitsharesAccountNameCacheRequest((GetBitsharesAccountNameCacheRequest) request);
+ } else {
- //TODO not implemented
- System.out.println("Error request not implemented " + request.getClass().getName());
+ //TODO not implemented
+ System.out.println("Error request not implemented " + request.getClass().getName());
+ }
}
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java
index 1a4c6fa..8beb806 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java
@@ -12,14 +12,25 @@ import org.bitcoinj.crypto.HDKeyDerivation;
import org.bitcoinj.script.Script;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import cy.agorise.crystalwallet.apigenerator.ApiRequest;
import cy.agorise.crystalwallet.apigenerator.ApiRequestListener;
import cy.agorise.crystalwallet.apigenerator.InsightApiGenerator;
import cy.agorise.crystalwallet.apigenerator.insightapi.BroadcastTransaction;
+import cy.agorise.crystalwallet.apigenerator.insightapi.GetTransactionData;
+import cy.agorise.crystalwallet.apigenerator.insightapi.models.Txi;
+import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin;
+import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout;
+import cy.agorise.crystalwallet.dao.CrystalDatabase;
+import cy.agorise.crystalwallet.enums.CryptoCoin;
+import cy.agorise.crystalwallet.models.BitcoinTransaction;
import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.models.GTxIO;
+import cy.agorise.crystalwallet.models.GeneralCoinAccount;
import cy.agorise.crystalwallet.models.GeneralCoinAddress;
import cy.agorise.crystalwallet.models.GeneralTransaction;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequest;
@@ -29,6 +40,28 @@ import cy.agorise.graphenej.Util;
public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener {
+ static HashMap generalAccountManagers = new HashMap();
+
+ private static CryptoCoin[] SUPPORTED_COINS = new CryptoCoin[]{
+ CryptoCoin.BITCOIN,
+ CryptoCoin.BITCOIN_TEST,
+ CryptoCoin.DASH,
+ CryptoCoin.LITECOIN
+ } ;
+
+ final CryptoCoin cryptoCoin;
+ final Context context;
+
+ public static GeneralAccountManager getAccountManager(CryptoCoin coin){
+ return generalAccountManagers.get(coin);
+ }
+
+ public GeneralAccountManager(CryptoCoin cryptoCoin, Context context) {
+ this.cryptoCoin = cryptoCoin;
+ this.context = context;
+ generalAccountManagers.put(cryptoCoin,this);
+ }
+
@Override
public void createAccountFromSeed(CryptoNetAccount account, ManagerRequest request, Context context) {
@@ -46,14 +79,131 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
@Override
public void onNewRequest(CryptoNetInfoRequest request) {
+ if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){
+ if(request instanceof GeneralAccountSendRequest){
+ this.send((GeneralAccountSendRequest)request);
+ }else{
+ System.out.println("Invalid " +this.cryptoCoin.getLabel() + " request ");
+ }
+ }
+
+ }
+
+ /**
+ * Class that process each transaction fetched by the insight api
+ * @param txi
+ */
+ public void processTxi(Txi txi){
+ CrystalDatabase db = CrystalDatabase.getAppDatabase(this.context);
+ BitcoinTransaction btTransaction = db.bitcoinTransactionDao().getByTxid(txi.txid);
+ if(btTransaction != null){
+ btTransaction.setConfirmations(txi.confirmations);
+ db.bitcoinTransactionDao().insertBitcoinTransaction(btTransaction);
+ }else {
+
+
+ GeneralTransaction transaction = new GeneralTransaction();
+ //transaction.setAccount(this.mAccount);
+ transaction.setTxid(txi.txid);
+ transaction.setBlock(txi.blockheight);
+ transaction.setDate(new Date(txi.time * 1000));
+ transaction.setFee((long) (txi.fee * Math.pow(10, cryptoCoin.getPrecision())));
+ transaction.setConfirm(txi.confirmations);
+ transaction.setType(cryptoCoin);
+ transaction.setBlockHeight(txi.blockheight);
+
+ for (Vin vin : txi.vin) {
+ GTxIO input = new GTxIO();
+ input.setAmount((long) (vin.value * Math.pow(10, cryptoCoin.getPrecision())));
+ input.setTransaction(transaction);
+ input.setOut(true);
+ input.setType(cryptoCoin);
+ String addr = vin.addr;
+ input.setAddressString(addr);
+ input.setIndex(vin.n);
+ input.setScriptHex(vin.scriptSig.hex);
+ input.setOriginalTxid(vin.txid);
+ /*for (GeneralCoinAddress address : this.mAddresses) {
+ if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) {
+ input.setAddress(address);
+ tempAccount = address.getAccount();
+
+ if (!address.hasTransactionOutput(input, this.mAccount.getNetworkParam())) {
+ address.getTransactionOutput().add(input);
+ }
+ }
+ }*/
+ transaction.getTxInputs().add(input);
+ }
+
+ for (Vout vout : txi.vout) {
+ if (vout.scriptPubKey.addresses == null || vout.scriptPubKey.addresses.length <= 0) {
+ // The address is null, this must be a memo
+ String hex = vout.scriptPubKey.hex;
+ int opReturnIndex = hex.indexOf("6a");
+ if (opReturnIndex >= 0) {
+ byte[] memoBytes = new byte[Integer.parseInt(hex.substring(opReturnIndex + 2, opReturnIndex + 4), 16)];
+ for (int i = 0; i < memoBytes.length; i++) {
+ memoBytes[i] = Byte.parseByte(hex.substring(opReturnIndex + 4 + (i * 2), opReturnIndex + 6 + (i * 2)), 16);
+ }
+ transaction.setMemo(new String(memoBytes));
+ }
+ } else {
+ GTxIO output = new GTxIO();
+ output.setAmount((long) (vout.value * Math.pow(10, cryptoCoin.getPrecision())));
+ output.setTransaction(transaction);
+ output.setOut(false);
+ output.setType(cryptoCoin);
+ String addr = vout.scriptPubKey.addresses[0];
+ output.setAddressString(addr);
+ output.setIndex(vout.n);
+ output.setScriptHex(vout.scriptPubKey.hex);
+ /*for (GeneralCoinAddress address : this.mAddresses) {
+ if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) {
+ output.setAddress(address);
+ tempAccount = address.getAccount();
+
+ if (!address.hasTransactionInput(output, this.mAccount.getNetworkParam())) {
+ address.getTransactionInput().add(output);
+ }
+ changed = true;
+ }
+ }*/
+
+ transaction.getTxOutputs().add(output);
+ }
+ }
+ if (txi.txlock && txi.confirmations < cryptoCoin.getCryptoNet().getConfirmationsNeeded()) {
+ transaction.setConfirm(cryptoCoin.getCryptoNet().getConfirmationsNeeded());
+ }
+ //TODO database
+ /*SCWallDatabase db = new SCWallDatabase(this.mContext);
+ long idTransaction = db.getGeneralTransactionId(transaction);
+ if (idTransaction == -1) {
+ db.putGeneralTransaction(transaction);
+ } else {
+ transaction.setId(idTransaction);
+ db.updateGeneralTransaction(transaction);
+ }*/
+
+ /*if (tempAccount != null && transaction.getConfirm() < this.mAccount.getCryptoNet().getConfirmationsNeeded()) {
+ InsightApiGenerator.followTransaction();
+ new GetTransactionData(transaction.getTxid(), tempAccount, this.serverUrl, this.mContext, true).start();
+ }
+ for (GeneralCoinAddress address : this.mAddresses) {
+ if (address.updateTransaction(transaction)) {
+ break;
+ }
+ }*/
+ }
}
public void send(final GeneralAccountSendRequest request){
//TODO check server connection
//TODO validate to address
- InsightApiGenerator.getEstimateFee(request.getAccount().getCryptoNet(),new ApiRequest(1, new ApiRequestListener() {
+ InsightApiGenerator.getEstimateFee(request.getAccount().getCryptoCoin(),new ApiRequest(1, new ApiRequestListener() {
@Override
public void success(Object answer, int idPetition) {
Transaction tx = new Transaction(request.getAccount().getNetworkParam());
@@ -122,7 +272,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
tx.addSignedInput(outPoint, script, utxo.getAddress().getKey(), Transaction.SigHash.ALL, true);
}
- InsightApiGenerator.broadcastTransaction(request.getAccount().getCryptoNet(),Util.bytesToHex(tx.bitcoinSerialize()),new ApiRequest(1, new ApiRequestListener() {
+ InsightApiGenerator.broadcastTransaction(request.getAccount().getCryptoCoin(),Util.bytesToHex(tx.bitcoinSerialize()),new ApiRequest(1, new ApiRequestListener() {
@Override
public void success(Object answer, int idPetition) {
request.setStatus(GeneralAccountSendRequest.StatusCode.SUCCEEDED);
diff --git a/app/src/main/java/cy/agorise/crystalwallet/models/BitcoinTransaction.java b/app/src/main/java/cy/agorise/crystalwallet/models/BitcoinTransaction.java
new file mode 100644
index 0000000..e7ed29b
--- /dev/null
+++ b/app/src/main/java/cy/agorise/crystalwallet/models/BitcoinTransaction.java
@@ -0,0 +1,110 @@
+package cy.agorise.crystalwallet.models;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.ForeignKey;
+import android.arch.persistence.room.Ignore;
+import android.arch.persistence.room.Index;
+import android.arch.persistence.room.PrimaryKey;
+import android.support.annotation.NonNull;
+import android.support.v7.util.DiffUtil;
+
+import java.util.Date;
+
+/**
+ * Represents a Bitcoin alike Transaction
+ *
+ * Created by Henry Varona on 10/2/2018.
+ */
+@Entity(
+ tableName="bitcoin_transaction",
+ primaryKeys = {"crypto_coin_transaction_id"},
+ foreignKeys = {
+ @ForeignKey(
+ entity = CryptoCoinTransaction.class,
+ parentColumns = "id",
+ childColumns = "crypto_coin_transaction_id",
+ onDelete = ForeignKey.CASCADE
+ )
+ }
+)
+public class BitcoinTransaction {
+
+ /**
+ * The id of the base transaction
+ */
+ @ColumnInfo(name="crypto_coin_transaction_id")
+ protected long cryptoCoinTransactionId;
+
+
+ /**
+ * The transaction id in the blockchain
+ */
+ @ColumnInfo(name="tx_id")
+ @NonNull protected String txId;
+
+ /**
+ * The block id in the blockchain
+ */
+ @ColumnInfo(name="block")
+ protected long block;
+
+ /**
+ * The fee of the transaction
+ */
+ @ColumnInfo(name="fee")
+ protected long fee;
+ /**
+ * The confirmations of the transaction in the blockchain
+ */
+ @ColumnInfo(name="confirmations")
+ protected int confirmations;
+
+ public BitcoinTransaction(long cryptoCoinTransactionId, String txId, long block, long fee, int confirmations) {
+ this.cryptoCoinTransactionId = cryptoCoinTransactionId;
+ this.txId = txId;
+ this.block = block;
+ this.fee = fee;
+ this.confirmations = confirmations;
+ }
+
+ public long getCryptoCoinTransactionId() {
+ return cryptoCoinTransactionId;
+ }
+
+ public void setCryptoCoinTransactionId(long cryptoCoinTransactionId) {
+ this.cryptoCoinTransactionId = cryptoCoinTransactionId;
+ }
+
+ public String getTxId() {
+ return txId;
+ }
+
+ public void setTxId(String txId) {
+ this.txId = txId;
+ }
+
+ public long getBlock() {
+ return block;
+ }
+
+ public void setBlock(long block) {
+ this.block = block;
+ }
+
+ public long getFee() {
+ return fee;
+ }
+
+ public void setFee(long fee) {
+ this.fee = fee;
+ }
+
+ public int getConfirmations() {
+ return confirmations;
+ }
+
+ public void setConfirmations(int confirmations) {
+ this.confirmations = confirmations;
+ }
+}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/models/BitcoinTransactionExtended.java b/app/src/main/java/cy/agorise/crystalwallet/models/BitcoinTransactionExtended.java
new file mode 100644
index 0000000..c2202bc
--- /dev/null
+++ b/app/src/main/java/cy/agorise/crystalwallet/models/BitcoinTransactionExtended.java
@@ -0,0 +1,26 @@
+package cy.agorise.crystalwallet.models;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Embedded;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.ForeignKey;
+import android.arch.persistence.room.Relation;
+
+import java.util.List;
+
+/**
+ * Represents a Bitcoin alike Transaction
+ *
+ * Created by Henry Varona on 10/2/2018.
+ */
+public class BitcoinTransactionExtended {
+
+ @Embedded
+ public CryptoCoinTransaction cryptoCoinTransaction;
+
+ @Embedded
+ public BitcoinTransaction bitcoinTransaction;
+
+ @Relation(parentColumn = "id", entityColumn = "bitcoin_transaction_id", entity = BitcoinTransactionGTxIO.class)
+ public List bitcoinTransactionGTxIOList;
+}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/models/BitcoinTransactionGTxIO.java b/app/src/main/java/cy/agorise/crystalwallet/models/BitcoinTransactionGTxIO.java
new file mode 100644
index 0000000..8febad2
--- /dev/null
+++ b/app/src/main/java/cy/agorise/crystalwallet/models/BitcoinTransactionGTxIO.java
@@ -0,0 +1,88 @@
+package cy.agorise.crystalwallet.models;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.ForeignKey;
+
+/**
+ * Represents a Bitcoin alike Transaction Inputs and Outputs
+ *
+ * Created by Henry Varona on 10/2/2018.
+ */
+@Entity(
+ tableName="bitcoin_transaction_gt_io",
+ primaryKeys = {"bitcoin_transaction_id", "io_index", "is_output"},
+ foreignKeys = {
+ @ForeignKey(
+ entity = BitcoinTransaction.class,
+ parentColumns = "crypto_coin_transaction_id",
+ childColumns = "bitcoin_transaction_id",
+ onDelete = ForeignKey.CASCADE
+ )
+ }
+)
+public class BitcoinTransactionGTxIO {
+
+ /**
+ * The id of the bitcoin transaction
+ */
+ @ColumnInfo(name="bitcoin_transaction_id")
+ protected long bitcoinTransactionId;
+
+ /**
+ * The index in the transaction
+ */
+ @ColumnInfo(name="io_index")
+ protected int index;
+
+ /**
+ * The address of the input or output
+ */
+ @ColumnInfo(name="address")
+ protected String address;
+
+ /**
+ * determines if this is an input or output
+ */
+ @ColumnInfo(name="is_output")
+ protected boolean isOutput;
+
+ public BitcoinTransactionGTxIO(long bitcoinTransactionId, int index, String address, boolean isOutput) {
+ this.bitcoinTransactionId = bitcoinTransactionId;
+ this.index = index;
+ this.address = address;
+ this.isOutput = isOutput;
+ }
+
+ public long getBitcoinTransactionId() {
+ return bitcoinTransactionId;
+ }
+
+ public void setBitcoinTransactionId(long bitcoinTransactionId) {
+ this.bitcoinTransactionId = bitcoinTransactionId;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public boolean isOutput() {
+ return isOutput;
+ }
+
+ public void setOutput(boolean output) {
+ isOutput = output;
+ }
+}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/CryptoNetInfoRequest.java b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/CryptoNetInfoRequest.java
index f45a5b1..23f88f8 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/CryptoNetInfoRequest.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/CryptoNetInfoRequest.java
@@ -21,13 +21,6 @@ public abstract class CryptoNetInfoRequest {
*/
protected CryptoNetInfoRequestListener listener;
-
-
-
-
-
-
-
protected CryptoNetInfoRequest(CryptoCoin coin){
this.coin = coin;
}
@@ -43,4 +36,7 @@ public abstract class CryptoNetInfoRequest {
CryptoNetInfoRequests.getInstance().removeRequest(this);
}
+ public CryptoCoin getCoin() {
+ return coin;
+ }
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java
index 954933b..fbab252 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java
@@ -105,12 +105,19 @@ public class CryptoCoinBalanceViewHolder extends RecyclerView.ViewHolder {
public void onChanged(@Nullable CryptoCurrencyEquivalence cryptoCurrencyEquivalence) {
if (cryptoCurrencyEquivalence != null) {
CryptoCurrency toCurrency = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getById(cryptoCurrencyEquivalence.getFromCurrencyId());
- double equivalentValue = (balance.getBalance() / Math.pow(10, currencyFrom.getPrecision())) /
- (cryptoCurrencyEquivalence.getValue() / Math.pow(10, toCurrency.getPrecision()));
- String equivalenceString = String.format(
- "%.2f",
- equivalentValue
- );
+ double equivalentValue = 0;
+ String equivalenceString = "";
+ if (cryptoCurrencyEquivalence.getValue() > 0) {
+ equivalentValue = (balance.getBalance() / Math.pow(10, currencyFrom.getPrecision())) /
+ (cryptoCurrencyEquivalence.getValue() / Math.pow(10, toCurrency.getPrecision()));
+ equivalenceString = String.format(
+ "%.2f",
+ equivalentValue
+ );
+ } else {
+ equivalentValue = 0;
+ equivalenceString = "0";
+ }
cryptoNetBalanceViewHolder.setEquivalentBalance(balance,equivalentValue);
cryptoCoinBalanceEquivalence.setText(
diff --git a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java
index 4a2043c..4a2e126 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java
@@ -3,6 +3,7 @@ package cy.agorise.crystalwallet.views;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.LiveData;
@@ -24,12 +25,14 @@ import butterknife.ButterKnife;
import butterknife.OnClick;
import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.activities.SendTransactionActivity;
+import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.fragments.ReceiveTransactionFragment;
import cy.agorise.crystalwallet.fragments.SendTransactionFragment;
import cy.agorise.crystalwallet.models.CryptoCoinBalance;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
import cy.agorise.crystalwallet.models.CryptoCurrencyEquivalence;
import cy.agorise.crystalwallet.models.CryptoNetBalance;
+import cy.agorise.crystalwallet.models.GeneralSetting;
import cy.agorise.crystalwallet.viewmodels.CryptoCoinBalanceListViewModel;
/**
@@ -86,6 +89,8 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
*/
private Fragment fragment;
+ String preferredCurrency = "";
+
public CryptoNetBalanceViewHolder(View itemView, Fragment fragment) {
super(itemView);
//-1 represents a crypto net account not loaded yet
@@ -114,6 +119,18 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
});
this.fragment = fragment;
this.context = itemView.getContext();
+
+ LiveData preferedCurrencySetting = CrystalDatabase.getAppDatabase(this.context).generalSettingDao().getByName(GeneralSetting.SETTING_NAME_PREFERRED_CURRENCY);
+
+ preferedCurrencySetting.observe((LifecycleOwner)this.itemView.getContext(), new Observer() {
+ @Override
+ public void onChanged(@Nullable GeneralSetting generalSetting) {
+ if(generalSetting != null){
+ preferredCurrency = generalSetting.getValue();
+ }
+ }
+ });
+
}
public void clear(){
@@ -179,7 +196,7 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder {
totalEquivalent += nextEquivalent;
}
- this.cryptoNetEquivalentTotal.setText(""+totalEquivalent);
+ this.cryptoNetEquivalentTotal.setText(""+totalEquivalent+" "+preferredCurrency);
}
}
diff --git a/app/src/main/res/layout/crypto_net_account_activity_settings.xml b/app/src/main/res/layout/crypto_net_account_activity_settings.xml
index d832726..425946c 100644
--- a/app/src/main/res/layout/crypto_net_account_activity_settings.xml
+++ b/app/src/main/res/layout/crypto_net_account_activity_settings.xml
@@ -56,8 +56,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
- android:text="Account Settings"
- android:textColor="@color/gray"
+ android:text="@string/Account_Settings"
+ android:textColor="@color/semiTransparentWhite"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/app/src/main/res/layout/fragment_general_crypto_net_account_settings.xml b/app/src/main/res/layout/fragment_general_crypto_net_account_settings.xml
index 023303d..fde0910 100644
--- a/app/src/main/res/layout/fragment_general_crypto_net_account_settings.xml
+++ b/app/src/main/res/layout/fragment_general_crypto_net_account_settings.xml
@@ -1,32 +1,67 @@
-
-
+ android:background="@color/white"
+ android:padding="20dp"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true">
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_import_account_options.xml b/app/src/main/res/layout/fragment_import_account_options.xml
index dc12e70..0ed744c 100644
--- a/app/src/main/res/layout/fragment_import_account_options.xml
+++ b/app/src/main/res/layout/fragment_import_account_options.xml
@@ -32,9 +32,10 @@
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
- app:layout_constraintTop_toBottomOf="@id/tvDescription"
+ app:layout_constraintEnd_toEndOf="@id/tvDescription"
+ app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@id/tvDescription"
- app:layout_constraintEnd_toEndOf="@id/tvDescription"/>
+ app:layout_constraintTop_toBottomOf="@id/tvDescription" />
You dont have contacts
+ Permission Denied, You cannot use local drive.
+
ACCOUNT CREATE/REGISTER OR IMPORT
Account Name
Time stamp
@@ -362,6 +364,9 @@
To display a photo for this Contact, enter its Gravatar e-mail here
Copied to Clipboard
+ Permission Denied. You cannot use the QR camera. Please allow this permission in App Settings.
+ Great!! Now you can use the QR camera.
+
"Select
"Are you sure?
is already added
@@ -523,6 +528,7 @@
Account already exists
Connection status
People icon
+ Account Settings
Camera feed to scan QR
Create Account
Import Account
diff --git a/build.gradle b/build.gradle
index 635a6c8..a977936 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,9 +8,9 @@ buildscript {
}
ext.kotlin_version = '1.2.51'
dependencies {
- classpath 'com.android.tools.build:gradle:3.1.4'
+ classpath 'com.android.tools.build:gradle:3.2.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.60"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.51"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 8163bd9..6e57679 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip