diff --git a/app/build.gradle b/app/build.gradle index 111fdd0..4cffbf7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,8 +22,8 @@ android { applicationId "cy.agorise.crystalwallet" minSdkVersion 21 targetSdkVersion 27 - versionCode 4 - versionName "0.4M.alpha" + versionCode 5 + versionName "0.5M.alpha" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary true @@ -87,6 +87,7 @@ dependencies { implementation 'com.jakewharton:butterknife:8.8.1' implementation 'com.github.bilthon:graphenej:0.4.6' implementation 'me.dm7.barcodescanner:zxing:1.9.8' + implementation 'com.github.sjaramillo10:AnimatedTabLayout:1.0.3' implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0' @@ -125,4 +126,7 @@ dependencies { annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' debugImplementation 'com.amitshekhar.android:debug-db:1.0.4' + + implementation 'com.google.zxing:core:3.2.1' + implementation 'com.journeyapps:zxing-android-embedded:3.2.0@aar' } 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 d8bfc68..704354f 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java +++ b/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java @@ -17,6 +17,7 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import cy.agorise.crystalwallet.R; +import cy.agorise.crystalwallet.application.CrystalSecurityMonitor; import cy.agorise.crystalwallet.fragments.ImportAccountOptionsFragment; import cy.agorise.crystalwallet.viewmodels.AccountSeedListViewModel; @@ -69,6 +70,9 @@ public class IntroActivity extends CustomActivity { } } ); + + this.getApplication().registerActivityLifecycleCallbacks(CrystalSecurityMonitor.getInstance(this)); + //Checks if the user has any seed created AccountSeedListViewModel accountSeedListViewModel = ViewModelProviders.of(this).get(AccountSeedListViewModel.class); diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/BitsharesFaucetApiGenerator.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/BitsharesFaucetApiGenerator.java index 7ce7f5e..5b2b6d2 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/BitsharesFaucetApiGenerator.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/BitsharesFaucetApiGenerator.java @@ -219,7 +219,7 @@ public abstract class BitsharesFaucetApiGenerator { public interface IWebService { @Headers({"Content-Type: application/json"}) - @POST("/api/v1/accounts") + @POST("/faucet/api/v1/accounts") Call getReg(@Body Map params); } 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 8d5ab13..355dc6f 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java @@ -75,7 +75,7 @@ public class InsightApiGenerator { GetEstimateFee.getEstimateFee(CryptoNetManager.getURL(cryptoCoin.getCryptoNet()), new GetEstimateFee.estimateFeeListener() { @Override - public void estimateFee(long value) { + public void estimateFee(double value) { request.listener.success(value,request.getId()); } 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 c4fa9cc..75910d6 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 @@ -65,9 +65,14 @@ public class BroadcastTransaction extends Thread implements Callback { */ @Override public void run() { - InsightApiService service = this.mServiceGenerator.getService(InsightApiService.class); - Call broadcastTransaction = service.broadcastTransaction(this.mPath,this.mRawTx); - broadcastTransaction.enqueue(this); + try { + + InsightApiService service = this.mServiceGenerator.getService(InsightApiService.class); + Call broadcastTransaction = service.broadcastTransaction(this.mPath, this.mRawTx); + broadcastTransaction.enqueue(this); + }catch(Exception e){ + e.printStackTrace(); + } } public interface BroadCastTransactionListener{ diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetEstimateFee.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetEstimateFee.java index dccb4dd..e827d73 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetEstimateFee.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetEstimateFee.java @@ -35,7 +35,7 @@ public abstract class GetEstimateFee { call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { - listener.estimateFee((long) (response.body().get("2").getAsDouble())); + listener.estimateFee((double) (response.body().get("2").getAsDouble())); } @@ -46,12 +46,13 @@ public abstract class GetEstimateFee { } }); }catch(Exception e){ + e.printStackTrace(); listener.fail(); } } public static interface estimateFeeListener{ - public void estimateFee(long value); + public void estimateFee(double value); public void fail(); } diff --git a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java index 5240ea1..4a96646 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java +++ b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java @@ -52,8 +52,10 @@ public class CrystalApplication extends Application { public static final String BITCOIN_SERVER_URLS[] ={ - "https://insight.bitpay.com/", - "https://testnet.blockexplorer.com/" + "https://test-insight.bitpay.com", + //"https://testnet.blockexplorer.com/", + //"https://insight.bitpay.com/" + }; public static final CryptoCurrency BITCOIN_CURRENCY = new CryptoCurrency("BTC",CryptoNet.BITCOIN,8); @@ -135,6 +137,11 @@ public class CrystalApplication extends Application { resources.updateConfiguration(configuration, dm); } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + Intent intent = new Intent(getApplicationContext(), CrystalWalletService.class); startService(intent); } diff --git a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java index 9f6297b..b0fa597 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java +++ b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java @@ -175,6 +175,8 @@ public class CrystalSecurityMonitor implements Application.ActivityLifecycleCall if(onResponsePattern != null){ PatternRequestActivity.setOnResponse(onResponsePattern); } + } else { + onResponsePattern.onSuccess(); } if (intent != null) { intent.putExtra("ACTIVITY_TYPE", "PASSWORD_REQUEST"); 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 1b224ec..b9e47cf 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/dao/CrystalDatabase.java +++ b/app/src/main/java/cy/agorise/crystalwallet/dao/CrystalDatabase.java @@ -72,10 +72,10 @@ public abstract class CrystalDatabase extends RoomDatabase { Room.databaseBuilder(context, CrystalDatabase.class, "CrystalWallet.db") .allowMainThreadQueries() - .addMigrations(MIGRATION_2_3) - .addMigrations(MIGRATION_3_4) - .addMigrations(MIGRATION_4_5) - .addMigrations(MIGRATION_5_6) + //.addMigrations(MIGRATION_2_3) + //.addMigrations(MIGRATION_3_4) + //.addMigrations(MIGRATION_4_5) + //.addMigrations(MIGRATION_5_6) .build(); } return instance; diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/ReceiveTransactionFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/ReceiveTransactionFragment.java index 8a78d5a..4a0c493 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/ReceiveTransactionFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/ReceiveTransactionFragment.java @@ -27,6 +27,7 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; +import android.widget.ProgressBar; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; @@ -35,6 +36,7 @@ import com.google.zxing.BarcodeFormat; import com.google.zxing.MultiFormatWriter; import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; +import com.journeyapps.barcodescanner.BarcodeEncoder; import butterknife.OnClick; import cy.agorise.crystalwallet.enums.CryptoCoin; @@ -84,6 +86,8 @@ public class ReceiveTransactionFragment extends DialogFragment implements UIVali TextView tvAssetError; @BindView(R.id.ivQrCode) ImageView ivQrCode; + @BindView(R.id.pbQrCode) + ProgressBar pbQrCode; @BindView(R.id.tvCancel) TextView tvCancel; @@ -106,6 +110,8 @@ public class ReceiveTransactionFragment extends DialogFragment implements UIVali private AsyncTask qrCodeTask; + private Double lastAmount = -1.0; + public static ReceiveTransactionFragment newInstance(long cryptoNetAccountId) { ReceiveTransactionFragment f = new ReceiveTransactionFragment(); @@ -337,144 +343,147 @@ public class ReceiveTransactionFragment extends DialogFragment implements UIVali } public void createQrCode(){ - Double amount = 0.0; + final Double amount; try{ amount = Double.valueOf(this.etAmount.getText().toString()); + } catch(NumberFormatException e){ + lastAmount = -1.0; Log.e("ReceiveFragment","Amount casting error."); + return; } - CryptoNetAccount toAccountSelected = (CryptoNetAccount) spTo.getSelectedItem(); - - if (this.cryptoNetAccount.getCryptoNet() == CryptoNet.BITSHARES) { - /* - * this is only for graphene accounts. - * - **/ - GrapheneAccount grapheneAccountSelected = new GrapheneAccount(toAccountSelected); - grapheneAccountSelected.loadInfo(db.grapheneAccountInfoDao().getByAccountId(toAccountSelected.getId())); - - - this.invoiceItems.clear(); - this.invoiceItems.add( - new LineItem("transfer", 1, amount) - ); - - LineItem items[] = new LineItem[this.invoiceItems.size()]; - items = this.invoiceItems.toArray(items); - this.invoice.setLineItems(items); - this.invoice.setTo(grapheneAccountSelected.getName()); - this.invoice.setCurrency(this.cryptoCurrency.getName()); + if (!amount.equals(lastAmount)) { + pbQrCode.setVisibility(View.VISIBLE); + lastAmount = amount; + CryptoNetAccount toAccountSelected = (CryptoNetAccount) spTo.getSelectedItem(); if (this.qrCodeTask != null) { this.qrCodeTask.cancel(true); } - this.qrCodeTask = new AsyncTask() { + if (this.cryptoNetAccount.getCryptoNet() == CryptoNet.BITSHARES) { + /* + * this is only for graphene accounts. + * + **/ + GrapheneAccount grapheneAccountSelected = new GrapheneAccount(toAccountSelected); + grapheneAccountSelected.loadInfo(db.grapheneAccountInfoDao().getByAccountId(toAccountSelected.getId())); - @Override - protected Void doInBackground(Object... voids) { - try { - final Bitmap bitmap = textToImageEncode(Invoice.toQrCode(invoice)); - if (!this.isCancelled()) { - ReceiveTransactionFragment.this.getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - ivQrCode.setImageBitmap(bitmap); - } - }); - } - } catch (WriterException e) { - Log.e("ReceiveFragment", "Error creating QrCode"); - } - return null; - } - }; + this.invoiceItems.clear(); + this.invoiceItems.add( + new LineItem("transfer", 1, amount) + ); - this.qrCodeTask.execute(null, null, null); - } else { - final CryptoCoin cryptoCoin = CryptoCoin.getByCryptoNet(this.cryptoNetAccount.getCryptoNet()).get(0); + LineItem items[] = new LineItem[this.invoiceItems.size()]; + items = this.invoiceItems.toArray(items); + this.invoice.setLineItems(items); + this.invoice.setTo(grapheneAccountSelected.getName()); + this.invoice.setCurrency(this.cryptoCurrency.getName()); - //final NextBitcoinAccountAddressRequest addressRequest = new NextBitcoinAccountAddressRequest(this.cryptoNetAccount, cryptoCoin, getContext()); + //if (this.qrCodeTask != null) { + // this.qrCodeTask.cancel(true); + //} - //addressRequest.setListener(new CryptoNetInfoRequestListener() { - // @Override - // public void onCarryOut() { - // if (addressRequest.getStatus() == NextBitcoinAccountAddressRequest.StatusCode.SUCCEEDED){ - final CalculateBitcoinUriRequest uriRequest = new CalculateBitcoinUriRequest(cryptoCoin, cryptoNetAccount, getContext(), amount); + this.qrCodeTask = new AsyncTask() { - uriRequest.setListener(new CryptoNetInfoRequestListener(){ - @Override - public void onCarryOut(){ - if (uriRequest.getUri() != null){ - qrCodeTask = new AsyncTask() { + @Override + protected Void doInBackground(Object... voids) { + try { + final Bitmap bitmap = textToImageEncode(Invoice.toQrCode(invoice)); - @Override - protected Void doInBackground(Object... voids) { - try { - final Bitmap bitmap = textToImageEncode(uriRequest.getUri()); - - if (!this.isCancelled()) { - ReceiveTransactionFragment.this.getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - ivQrCode.setImageBitmap(bitmap); - } - }); - } - } catch (WriterException e) { - Log.e("ReceiveFragment", "Error creating QrCode"); - } - return null; - } - }; - - qrCodeTask.execute(null, null, null); - } else { - Log.e("ReceiveFragment", "Error obtaining the uri"); - } + if (!this.isCancelled()) { + ReceiveTransactionFragment.this.getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + ivQrCode.setImageBitmap(bitmap); + pbQrCode.setVisibility(View.GONE); + } + }); } - }); + } catch (WriterException e) { + Log.e("ReceiveFragment", "Error creating QrCode"); + } + return null; + } + }; + + this.qrCodeTask.execute(null, null, null); + } else { + final CryptoCoin cryptoCoin = CryptoCoin.getByCryptoNet(this.cryptoNetAccount.getCryptoNet()).get(0); + + final CalculateBitcoinUriRequest uriRequest = new CalculateBitcoinUriRequest(cryptoCoin, cryptoNetAccount, getContext(), amount); + + uriRequest.setListener(new CryptoNetInfoRequestListener() { + @Override + public void onCarryOut() { + if (uriRequest.getUri() != null) { + qrCodeTask = new AsyncTask() { + + @Override + protected Void doInBackground(Object... voids) { + try { + final Bitmap bitmap = textToImageEncode(uriRequest.getUri()); + + if (!this.isCancelled()) { + ReceiveTransactionFragment.this.getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + //Double amountNow = -1.0; + //try{ + // amountNow = Double.valueOf(etAmount.getText().toString()); + //} catch(NumberFormatException e){ + //} + //if (amountNow >= 0) { + if (amount.equals(lastAmount)) { + if (!isCancelled()) { + ivQrCode.setImageBitmap(bitmap); + pbQrCode.setVisibility(View.GONE); + } + } + //} + } + }); + } + } catch (WriterException e) { + Log.e("ReceiveFragment", "Error creating QrCode"); + } + + return null; + } + }; + + qrCodeTask.execute(null, null, null); + } else { + Log.e("ReceiveFragment", "Error obtaining the uri"); + } + } + }); + + Thread thread = new Thread(new Runnable() { + @Override + public void run() { CryptoNetInfoRequests.getInstance().addRequest(uriRequest); - // } else { - // Toast.makeText(getContext(),"Error creating address",Toast.LENGTH_SHORT); - // } - // } - //}); + } + }); + thread.start(); + } } } Bitmap textToImageEncode(String Value) throws WriterException { - //TODO: do this in another thread - - BitMatrix bitMatrix; + Bitmap bitmap = null; + MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); try { - bitMatrix = new MultiFormatWriter().encode( - Value, - BarcodeFormat.DATA_MATRIX.QR_CODE, - ivQrCode.getWidth(), ivQrCode.getHeight(), null - ); - - } catch (IllegalArgumentException Illegalargumentexception) { - return null; - } - int bitMatrixWidth = bitMatrix.getWidth(); - int bitMatrixHeight = bitMatrix.getHeight(); - int[] pixels = new int[bitMatrixWidth * bitMatrixHeight]; - - for (int y = 0; y < bitMatrixHeight; y++) { - int offset = y * bitMatrixWidth; - - for (int x = 0; x < bitMatrixWidth; x++) { - pixels[offset + x] = bitMatrix.get(x, y) ? - getResources().getColor(R.color.QRCodeBlackColor):getResources().getColor(R.color.QRCodeWhiteColor); - } + BitMatrix bitMatrix = multiFormatWriter.encode(Value, BarcodeFormat.QR_CODE, ivQrCode.getWidth(), ivQrCode.getHeight()); + BarcodeEncoder barcodeEncoder = new BarcodeEncoder(); + bitmap = barcodeEncoder.createBitmap(bitMatrix); + } catch (WriterException e) { + e.printStackTrace(); } - Bitmap bitmap = Bitmap.createBitmap(bitMatrixWidth, bitMatrixHeight, Bitmap.Config.ARGB_4444); - bitmap.setPixels(pixels, 0, ivQrCode.getWidth(), 0, 0, bitMatrixWidth, bitMatrixHeight); return bitmap; } } 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 6b26439..e6a1d04 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java @@ -591,7 +591,7 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat /* * If exists mode scurity show it and valide events in case of success or fail * */ - CrystalSecurityMonitor.getInstance(null).callPasswordRequest(this.getActivity(), new OnResponse() { + CrystalSecurityMonitor.getInstance(this.getActivity()).callPasswordRequest(this.getActivity(), new OnResponse() { @Override public void onSuccess() { @@ -611,6 +611,7 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat } }); + //CryptoNetInfoRequests.getInstance().addRequest(sendRequest); } } 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 b26b661..d89b942 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java @@ -90,6 +90,11 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI long idAccount = db.cryptoNetAccountDao().insertCryptoNetAccount(fetch)[0]; fetch.setId(idAccount); db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(fetch)); + AccountSeed seed = db.accountSeedDao().findById(grapheneAccount.getSeedId()); + if(seed.getName() == null || seed.getName().isEmpty()){ + seed.setName(grapheneAccount.getName()); + db.accountSeedDao().insertAccountSeed(seed); + } subscribeBitsharesAccount(fetch.getId(),fetch.getAccountId(),context); request.success(fetch); } @@ -130,6 +135,11 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI long[] idAccount = db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount); grapheneAccount.setId(idAccount[0]); db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount)); + AccountSeed seed = db.accountSeedDao().findById(grapheneAccount.getSeedId()); + if(seed.getName() == null || seed.getName().isEmpty()){ + seed.setName(grapheneAccount.getName()); + db.accountSeedDao().insertAccountSeed(seed); + } subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context); } @@ -149,6 +159,11 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI long idAccount = db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount)[0]; grapheneAccount.setId(idAccount); db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount)); + AccountSeed seed = db.accountSeedDao().findById(grapheneAccount.getSeedId()); + if(seed.getName() == null || seed.getName().isEmpty()){ + seed.setName(grapheneAccount.getName()); + db.accountSeedDao().insertAccountSeed(seed); + } subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context); } @@ -162,6 +177,11 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI long idAccount = db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount)[0]; grapheneAccount.setId(idAccount); db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount)); + AccountSeed seed = db.accountSeedDao().findById(grapheneAccount.getSeedId()); + if(seed.getName() == null || seed.getName().isEmpty()){ + seed.setName(grapheneAccount.getName()); + db.accountSeedDao().insertAccountSeed(seed); + } subscribeBitsharesAccount(grapheneAccount.getId(), grapheneAccount.getAccountId(), context); } } @@ -182,6 +202,11 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI info.setAccountId(fetch.getAccountId()); grapheneAccount.setAccountId(fetch.getAccountId()); db.grapheneAccountInfoDao().insertGrapheneAccountInfo(info); + AccountSeed seed = db.accountSeedDao().findById(grapheneAccount.getSeedId()); + if(seed.getName() == null || seed.getName().isEmpty()){ + seed.setName(grapheneAccount.getName()); + db.accountSeedDao().insertAccountSeed(seed); + } subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context); } @@ -212,6 +237,11 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI } }); }else{ + AccountSeed seed = db.accountSeedDao().findById(grapheneAccount.getSeedId()); + if(seed.getName() == null || seed.getName().isEmpty()){ + seed.setName(grapheneAccount.getName()); + db.accountSeedDao().insertAccountSeed(seed); + } subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context); } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/manager/FileBackupManager.java b/app/src/main/java/cy/agorise/crystalwallet/manager/FileBackupManager.java index b0944dd..106a310 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/FileBackupManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/FileBackupManager.java @@ -327,7 +327,6 @@ public class FileBackupManager implements FileServiceRequestsListener { public static byte[] decompress(byte[] inputBytes, int which) { InputStream in = null; try { - System.out.println("Bytes: "+Util.bytesToHex(inputBytes)); ByteArrayInputStream input = new ByteArrayInputStream(inputBytes); ByteArrayOutputStream output = new ByteArrayOutputStream(16*2048); if(which == Util.XZ) { 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 6af2174..42caaf7 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java @@ -98,7 +98,19 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf new ChildNumber(1, false)); CryptoCoinBalance balance = new CryptoCoinBalance(); - balance.setBalance(0); + long amount = 0; + List trransactions = db.transactionDao().getByIdAccount(account.getId()); + for(CryptoCoinTransaction transaction : trransactions){ + if(transaction.isConfirmed()){ + if(transaction.getInput()){ + amount += transaction.getAmount(); + }else{ + amount -= transaction.getAmount(); + } + + } + } + balance.setBalance(amount); balance.setCryptoCurrencyId(db.cryptoCurrencyDao().getByName(cryptoCoin.getLabel(),cryptoCoin.name()).getId()); balance.setAccountId(account.getId()); db.cryptoCoinBalanceDao().insertCryptoCoinBalance(balance); @@ -115,7 +127,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf address.setChange(false); address.setAccountId(account.getId()); address.setIndex(0); - String addressString =externalAddrKey.toAddress(this.cryptoCoin.getParameters()).toString(); + String addressString = externalAddrKey.toAddress(this.cryptoCoin.getParameters()).toString(); address.setAddress(addressString); db.bitcoinAddressDao().insertBitcoinAddresses(address); InsightApiGenerator.getTransactionFromAddress(cryptoCoin,addressString,true, @@ -149,6 +161,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf //if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){ if(request.getCoin().equals(this.cryptoCoin)){ if(request instanceof BitcoinSendRequest) { + this.send((BitcoinSendRequest) request); }else if(request instanceof CreateBitcoinAccountRequest){ this.createGeneralAccount((CreateBitcoinAccountRequest) request); }else if(request instanceof NextBitcoinAccountAddressRequest){ @@ -171,134 +184,141 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf * @param txi */ public void processTxi(Txi txi){ - CrystalDatabase db = CrystalDatabase.getAppDatabase(this.context); - List btTransactions = db.bitcoinTransactionDao().getTransactionsByTxid(txi.txid); - if(!btTransactions.isEmpty()){ - for(BitcoinTransaction btTransaction : btTransactions) { - btTransaction.setConfirmations(txi.confirmations); - CryptoCoinTransaction ccTransaction = db.transactionDao().getById(btTransaction.getCryptoCoinTransactionId()); - if (!ccTransaction.isConfirmed() && btTransaction.getConfirmations() >= cryptoCoin.getCryptoNet().getConfirmationsNeeded()) { - ccTransaction.setConfirmed(true); - db.transactionDao().insertTransaction(ccTransaction); - updateBalance(ccTransaction,(ccTransaction.getInput()?1:-1)*ccTransaction.getAmount(),db); - } + try { + System.out.println("GeneralAccountManager processingTxi " + txi.txid); + CrystalDatabase db = CrystalDatabase.getAppDatabase(this.context); + List btTransactions = db.bitcoinTransactionDao().getTransactionsByTxid(txi.txid); + if (!btTransactions.isEmpty()) { + System.out.println("GeneralAccountManager Transaction not null " + txi.txid); + for (BitcoinTransaction btTransaction : btTransactions) { + btTransaction.setConfirmations(txi.confirmations); + CryptoCoinTransaction ccTransaction = db.transactionDao().getById(btTransaction.getCryptoCoinTransactionId()); + if (!ccTransaction.isConfirmed() && btTransaction.getConfirmations() >= cryptoCoin.getCryptoNet().getConfirmationsNeeded()) { + ccTransaction.setConfirmed(true); + db.transactionDao().insertTransaction(ccTransaction); + updateBalance(ccTransaction, (ccTransaction.getInput() ? 1 : -1) * ccTransaction.getAmount(), db); + } - db.bitcoinTransactionDao().insertBitcoinTransaction(btTransaction); - } - }else { + db.bitcoinTransactionDao().insertBitcoinTransaction(btTransaction); + } + } else { /*List ccTransactions = new ArrayList(); btTransactions = new ArrayList();*/ //TODO transactions involving multiples accounts - CryptoCoinTransaction ccTransaction = new CryptoCoinTransaction(); - BitcoinTransaction btTransaction = new BitcoinTransaction(); - btTransaction.setTxId(txi.txid); - btTransaction.setBlock(txi.blockheight); - btTransaction.setFee((long) (txi.fee * Math.pow(10, cryptoCoin.getPrecision()))); - btTransaction.setConfirmations(txi.confirmations); - ccTransaction.setDate(new Date(txi.time * 1000)); - if(txi.txlock || txi.confirmations >= cryptoCoin.getCryptoNet().getConfirmationsNeeded()) { - ccTransaction.setConfirmed(true); - }else{ - ccTransaction.setConfirmed(false); - } - - ccTransaction.setInput(false); - - long amount = 0; - - - //transaction.setAccount(this.mAccount); - //transaction.setType(cryptoCoin); - List gtxios = new ArrayList(); - for (Vin vin : txi.vin) { - BitcoinTransactionGTxIO input = new BitcoinTransactionGTxIO(); - String addr = vin.addr; - input.setAddress(addr); - input.setIndex(vin.n); - input.setOutput(true); - input.setAmount((long) (vin.value * Math.pow(10, cryptoCoin.getPrecision()))); - input.setOriginalTxId(vin.txid); - input.setScriptHex(vin.scriptSig.hex); - - BitcoinAddress address = db.bitcoinAddressDao().getdadress(addr); - if(address != null){ - if(ccTransaction.getAccountId() < 0){ - ccTransaction.setAccountId(address.getAccountId()); - ccTransaction.setFrom(addr); - ccTransaction.setInput(false); - } - - if(ccTransaction.getAccountId()== address.getAccountId()){ - amount -= vin.value; - } - } - - if(ccTransaction.getFrom() == null || ccTransaction.getFrom().isEmpty()){ - ccTransaction.setFrom(addr); - } - - gtxios.add(input); - - - } - - for (Vout vout : txi.vout) { - if (vout.scriptPubKey.addresses == null || vout.scriptPubKey.addresses.length <= 0) { - + CryptoCoinTransaction ccTransaction = new CryptoCoinTransaction(); + BitcoinTransaction btTransaction = new BitcoinTransaction(); + btTransaction.setTxId(txi.txid); + btTransaction.setBlock(txi.blockheight); + btTransaction.setFee((long) (txi.fee * Math.pow(10, cryptoCoin.getPrecision()))); + btTransaction.setConfirmations(txi.confirmations); + ccTransaction.setDate(new Date(txi.time * 1000)); + if (txi.txlock || txi.confirmations >= cryptoCoin.getCryptoNet().getConfirmationsNeeded()) { + ccTransaction.setConfirmed(true); } else { - BitcoinTransactionGTxIO output = new BitcoinTransactionGTxIO(); - String addr = vout.scriptPubKey.addresses[0]; - output.setAddress(addr); - output.setIndex(vout.n); - output.setOutput(false); - output.setAmount((long) (vout.value * Math.pow(10, cryptoCoin.getPrecision()))); - output.setScriptHex(vout.scriptPubKey.hex); - output.setOriginalTxId(txi.txid); + ccTransaction.setConfirmed(false); + } + + ccTransaction.setInput(false); + + long amount = 0; + + + //transaction.setAccount(this.mAccount); + //transaction.setType(cryptoCoin); + List gtxios = new ArrayList(); + for (Vin vin : txi.vin) { + BitcoinTransactionGTxIO input = new BitcoinTransactionGTxIO(); + String addr = vin.addr; + input.setAddress(addr); + input.setIndex(vin.n); + input.setOutput(true); + input.setAmount((long) (vin.value * Math.pow(10, cryptoCoin.getPrecision()))); + input.setOriginalTxId(vin.txid); + input.setScriptHex(vin.scriptSig.hex); - gtxios.add(output); BitcoinAddress address = db.bitcoinAddressDao().getdadress(addr); - if(address != null){ - if(ccTransaction.getAccountId() < 0){ + if (address != null) { + if (ccTransaction.getAccountId() < 0) { ccTransaction.setAccountId(address.getAccountId()); - ccTransaction.setInput(true); - ccTransaction.setTo(addr); + ccTransaction.setFrom(addr); + ccTransaction.setInput(false); } - if(ccTransaction.getAccountId()== address.getAccountId()){ - amount += vout.value; + if (ccTransaction.getAccountId() == address.getAccountId()) { + amount -= (long) (vin.value * Math.pow(10, cryptoCoin.getPrecision())); } - }else{ - //TOOD multiple send address - if(ccTransaction.getTo() == null || ccTransaction.getTo().isEmpty()){ - ccTransaction.setTo(addr); + } + + if (ccTransaction.getFrom() == null || ccTransaction.getFrom().isEmpty()) { + ccTransaction.setFrom(addr); + } + + gtxios.add(input); + + + } + + for (Vout vout : txi.vout) { + if (vout.scriptPubKey.addresses == null || vout.scriptPubKey.addresses.length <= 0) { + + } else { + BitcoinTransactionGTxIO output = new BitcoinTransactionGTxIO(); + String addr = vout.scriptPubKey.addresses[0]; + output.setAddress(addr); + output.setIndex(vout.n); + output.setOutput(false); + output.setAmount((long) (vout.value * Math.pow(10, cryptoCoin.getPrecision()))); + output.setScriptHex(vout.scriptPubKey.hex); + output.setOriginalTxId(txi.txid); + + gtxios.add(output); + + BitcoinAddress address = db.bitcoinAddressDao().getdadress(addr); + if (address != null) { + if (ccTransaction.getAccountId() < 0) { + ccTransaction.setAccountId(address.getAccountId()); + ccTransaction.setInput(true); + ccTransaction.setTo(addr); + } + + if (ccTransaction.getAccountId() == address.getAccountId()) { + amount += (long) (vout.value * Math.pow(10, cryptoCoin.getPrecision())); + } + } else { + //TOOD multiple send address + if (ccTransaction.getTo() == null || ccTransaction.getTo().isEmpty()) { + ccTransaction.setTo(addr); + } } } } - } - ccTransaction.setAmount(amount); - CryptoCurrency currency = db.cryptoCurrencyDao().getByNameAndCryptoNet(this.cryptoCoin.name(), this.cryptoCoin.getCryptoNet().name()); - if (currency == null) { - currency = new CryptoCurrency(); - currency.setCryptoNet(this.cryptoCoin.getCryptoNet()); - currency.setName(this.cryptoCoin.name()); - currency.setPrecision(this.cryptoCoin.getPrecision()); - long idCurrency = db.cryptoCurrencyDao().insertCryptoCurrency(currency)[0]; - currency.setId(idCurrency); - } + ccTransaction.setAmount(amount); + CryptoCurrency currency = db.cryptoCurrencyDao().getByNameAndCryptoNet(this.cryptoCoin.getLabel(), this.cryptoCoin.getCryptoNet().name()); + if (currency == null) { + currency = new CryptoCurrency(); + currency.setCryptoNet(this.cryptoCoin.getCryptoNet()); + currency.setName(this.cryptoCoin.getLabel()); + currency.setPrecision(this.cryptoCoin.getPrecision()); + long idCurrency = db.cryptoCurrencyDao().insertCryptoCurrency(currency)[0]; + currency.setId(idCurrency); + } - ccTransaction.setIdCurrency((int)currency.getId()); + ccTransaction.setIdCurrency((int) currency.getId()); - long ccId = db.transactionDao().insertTransaction(ccTransaction)[0]; - btTransaction.setCryptoCoinTransactionId(ccId); - long btId = db.bitcoinTransactionDao().insertBitcoinTransaction(btTransaction)[0]; - for(BitcoinTransactionGTxIO gtxio : gtxios){ - gtxio.setBitcoinTransactionId(btId); - db.bitcoinTransactionDao().insertBitcoinTransactionGTxIO(gtxio); - } + long ccId = db.transactionDao().insertTransaction(ccTransaction)[0]; + btTransaction.setCryptoCoinTransactionId(ccId); + long btId = db.bitcoinTransactionDao().insertBitcoinTransaction(btTransaction)[0]; + for (BitcoinTransactionGTxIO gtxio : gtxios) { + gtxio.setBitcoinTransactionId(btId); + db.bitcoinTransactionDao().insertBitcoinTransactionGTxIO(gtxio); + } - if(ccTransaction.isConfirmed()) { - updateBalance(ccTransaction,amount,db); + if (ccTransaction.isConfirmed()) { + updateBalance(ccTransaction, amount, db); + } } + }catch(Exception e){ + e.printStackTrace(); } } @@ -318,11 +338,11 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf } private void updateBalance(CryptoCoinTransaction ccTransaction, long amount, CrystalDatabase db){ - CryptoCurrency currency = db.cryptoCurrencyDao().getByNameAndCryptoNet(this.cryptoCoin.name(), this.cryptoCoin.getCryptoNet().name()); + CryptoCurrency currency = db.cryptoCurrencyDao().getByNameAndCryptoNet(this.cryptoCoin.getLabel(), this.cryptoCoin.getCryptoNet().name()); if (currency == null) { currency = new CryptoCurrency(); currency.setCryptoNet(this.cryptoCoin.getCryptoNet()); - currency.setName(this.cryptoCoin.name()); + currency.setName(this.cryptoCoin.getLabel()); currency.setPrecision(this.cryptoCoin.getPrecision()); long idCurrency = db.cryptoCurrencyDao().insertCryptoCurrency(currency)[0]; currency.setId(idCurrency); @@ -360,7 +380,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf Transaction tx = new Transaction(cryptoCoin.getParameters()); long currentAmount = 0; long fee = -1; - long feeRate = (Long) answer; + long feeRate = (long)(((double)answer) * Math.pow(10,cryptoCoin.getPrecision())); fee = 226 * feeRate; CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext()); @@ -535,7 +555,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf System.out.println("GeneralAccountMAnager uri calculated : " + uri.toString()); request.setUri(uri.toString()); - request.validate(); + //request.validate(); } private void parseUri(BitcoinUriParseRequest request){ diff --git a/app/src/main/java/cy/agorise/crystalwallet/models/CryptoCoinTransaction.java b/app/src/main/java/cy/agorise/crystalwallet/models/CryptoCoinTransaction.java index 4b06ee4..3259d75 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/models/CryptoCoinTransaction.java +++ b/app/src/main/java/cy/agorise/crystalwallet/models/CryptoCoinTransaction.java @@ -20,9 +20,13 @@ import cy.agorise.crystalwallet.enums.CryptoCoin; */ @Entity( tableName="crypto_coin_transaction", + primaryKeys = { + + }, indices={ @Index(value={"account_id"}), - @Index(value={"id_currency"}) + @Index(value={"id_currency"}), + @Index(value={"date", "account_id", "id_currency", "from", "to"},unique=true) }, foreignKeys = { @ForeignKey( diff --git a/app/src/main/java/cy/agorise/crystalwallet/network/BitcoinCryptoNetVerifier.java b/app/src/main/java/cy/agorise/crystalwallet/network/BitcoinCryptoNetVerifier.java index d38bcfb..9ebd52a 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/network/BitcoinCryptoNetVerifier.java +++ b/app/src/main/java/cy/agorise/crystalwallet/network/BitcoinCryptoNetVerifier.java @@ -23,7 +23,7 @@ public class BitcoinCryptoNetVerifier extends CryptoNetVerifier{ CryptoNetManager.verifiedCryptoNetURL(cryptoCoin.getCryptoNet(), url, System.currentTimeMillis() - startTime); }else{ - System.out.println("BitcoinCryptoNetVerifier bad genesis block " + value); + System.out.println("BitcoinCryptoNetVerifier bad genesis block " + value + " " + url); } //TODO bad genesis block }else{ diff --git a/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetManager.java b/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetManager.java index 24bf672..544d1fb 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetManager.java @@ -32,7 +32,6 @@ public abstract class CryptoNetManager { public static String getURL(CryptoNet crypto, int index){ if(TestedURLs.containsKey(crypto) && TestedURLs.get(crypto).size()>index){ - System.out.println("Servers url list " + Arrays.toString(TestedURLs.get(crypto).toArray())); return TestedURLs.get(crypto).get(index).getUrl(); } System.out.println("Servers " + crypto.getLabel()+" dioesn't have testedurl"); diff --git a/app/src/main/java/cy/agorise/crystalwallet/network/GetChainId.java b/app/src/main/java/cy/agorise/crystalwallet/network/GetChainId.java index 2863514..044c05b 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/network/GetChainId.java +++ b/app/src/main/java/cy/agorise/crystalwallet/network/GetChainId.java @@ -38,7 +38,6 @@ public class GetChainId extends BaseGrapheneHandler { @Override public void onTextFrame(WebSocket websocket, WebSocketFrame frame) throws Exception { - System.out.println("<<< "+frame.getPayloadText()); String response = frame.getPayloadText(); Type GetChainIdResponse = new TypeToken>(){}.getType(); @@ -55,7 +54,5 @@ public class GetChainId extends BaseGrapheneHandler { @Override public void onFrameSent(WebSocket websocket, WebSocketFrame frame) throws Exception { - if(frame.isTextFrame()) - System.out.println(">>> "+frame.getPayloadText()); } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/network/GetDatabaseVersion.java b/app/src/main/java/cy/agorise/crystalwallet/network/GetDatabaseVersion.java index 6625030..8146e36 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/network/GetDatabaseVersion.java +++ b/app/src/main/java/cy/agorise/crystalwallet/network/GetDatabaseVersion.java @@ -38,7 +38,6 @@ public class GetDatabaseVersion extends BaseGrapheneHandler { @Override public void onTextFrame(WebSocket websocket, WebSocketFrame frame) throws Exception { - System.out.println("<<< "+frame.getPayloadText()); String response = frame.getPayloadText(); Type GetChainIdResponse = new TypeToken>(){}.getType(); @@ -55,8 +54,6 @@ public class GetDatabaseVersion extends BaseGrapheneHandler { @Override public void onFrameSent(WebSocket websocket, WebSocketFrame frame) throws Exception { - if(frame.isTextFrame()) - System.out.println(">>> "+frame.getPayloadText()); } public class VersionResponse{ diff --git a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/AmountValidationField.java b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/AmountValidationField.java index a01f1a8..f18592f 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/AmountValidationField.java +++ b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/validationfields/AmountValidationField.java @@ -5,6 +5,8 @@ import android.widget.Spinner; import cy.agorise.crystalwallet.R; import cy.agorise.crystalwallet.dao.CrystalDatabase; +import cy.agorise.crystalwallet.enums.CryptoCoin; +import cy.agorise.crystalwallet.enums.CryptoNet; import cy.agorise.crystalwallet.models.CryptoCoinBalance; import cy.agorise.crystalwallet.models.CryptoCurrency; import cy.agorise.crystalwallet.models.CryptoNetAccount; @@ -29,7 +31,12 @@ public class AmountValidationField extends ValidationField { public void validate(){ try { final float newAmountValue = Float.parseFloat(amountField.getText().toString()); - final CryptoCurrency cryptoCurrency = (CryptoCurrency)assetSpinner.getSelectedItem(); + final CryptoCurrency cryptoCurrency; + if(this.account.getCryptoNet() == CryptoNet.BITSHARES) { + cryptoCurrency = (CryptoCurrency) assetSpinner.getSelectedItem(); + }else{ + cryptoCurrency = CrystalDatabase.getAppDatabase(amountField.getContext()).cryptoCurrencyDao().getByNameAndCryptoNet(CryptoCoin.getByCryptoNet(this.account.getCryptoNet()).get(0).getLabel(),this.account.getCryptoNet().name()); + } /* * Validation for the money @@ -66,6 +73,8 @@ public class AmountValidationField extends ValidationField { setLastValue(""); setMessageForValue("",validator.getContext().getResources().getString(R.string.please_enter_valid_amount)); setValidForValue("", false); + } catch (Exception e ){ + e.printStackTrace(); } } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/views/TransactionViewHolder.java b/app/src/main/java/cy/agorise/crystalwallet/views/TransactionViewHolder.java index c105f50..4a3a14a 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/views/TransactionViewHolder.java +++ b/app/src/main/java/cy/agorise/crystalwallet/views/TransactionViewHolder.java @@ -10,7 +10,10 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import org.apache.commons.codec.binary.StringUtils; + import java.text.DateFormat; +import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.TimeZone; @@ -113,7 +116,12 @@ public class TransactionViewHolder extends RecyclerView.ViewHolder { CryptoNetAccountViewModel cryptoNetAccountViewModel = ViewModelProviders.of(this.fragment).get(CryptoNetAccountViewModel.class); cryptoNetAccountViewModel.loadCryptoNetAccount(transaction.getAccountId()); - String amountString = String.format("%.2f",transaction.getAmount()/Math.pow(10,cryptoCurrency.getPrecision())); + String pattern = new String(new char[cryptoCurrency.getPrecision()]).replace('\0', '#'); + pattern = "#."+pattern; + + DecimalFormat df = new DecimalFormat(pattern); + //String amountString = String.format("%.2f",transaction.getAmount()/Math.pow(10,cryptoCurrency.getPrecision())); + String amountString = df.format(transaction.getAmount()/Math.pow(10,cryptoCurrency.getPrecision())); GeneralSettingListViewModel generalSettingListViewModel = ViewModelProviders.of(this.fragment).get(GeneralSettingListViewModel.class); GeneralSetting timeZoneSetting = generalSettingListViewModel.getGeneralSettingByName(GeneralSetting.SETTING_NAME_TIME_ZONE); diff --git a/app/src/main/res/layout/receive_transaction.xml b/app/src/main/res/layout/receive_transaction.xml index 93c642d..2002da3 100644 --- a/app/src/main/res/layout/receive_transaction.xml +++ b/app/src/main/res/layout/receive_transaction.xml @@ -138,6 +138,22 @@ app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/tvAmountError" /> + +